home *** CD-ROM | disk | FTP | other *** search
/ Belgian Amiga Club - ADF Collection / BS1 part 60.zip / BS1 part 60 / LSD 31.adf / AmigaMachineLang2.pp / AmigaMachineLang2
Text File  |  1990-09-07  |  148KB  |  3,546 lines

  1.               _____          _________________________________
  2.              /    /\        /                                 \
  3.             /    / /       /    ___________________________    \
  4.            /    / /       /    / _________________________/\    \
  5.           /    / /       /    /_/___________      _____   \ \    \
  6.          /    / /       /                   \    /\    \   \ \    \
  7.         /    / /       /_________________    \   \ \    \   \ \    \
  8.        /    / /        \________________/\    \   \ \    \   \ \    \
  9.       /    /_/__________________________\_\    \   \ \    \___\/     \
  10.      /                                          \   \ \              / 
  11.     /____________________________________________\   \ \____________/
  12.     \____________________________________________/    \/___________/FISH
  13.  
  14.                                 P R E S E N T
  15.  
  16.                  AMIGA MACHINE LANGUAGE - FROM ABACUS BOOKS
  17.  
  18.                                 P A R T  I I
  19.  
  20.  
  21.                      Typed by DEE JAY of X-CELL for LSD
  22.  
  23.  
  24.  
  25.  
  26.       CHAPTER 5.
  27.       ---------
  28.       5.Hardware Registers.
  29.       --------------------
  30.         You can get information about hardware functions without using
  31.         library functions.You can use the hardware registers instead.These
  32.         are memory locations at particular addresses that are neither in
  33.         RAM nor in ROM.They are direct interfaces between the processor
  34.         and its peripheral devices.
  35.         Each device has a number of hardware registers that the processor
  36.         accesses to control graphics,sound and input/output.There are lots
  37.         of possibilities for assembly language programmers.We'll only be
  38.         able to go into a few examples.
  39.         The registers are generally used in byte-wise fashion.You'll find
  40.         an example in the next chapter.
  41.  
  42.       5.1.Checking For Special Keys.
  43.       -----------------------------
  44.         Load AssemPro and enter the debugger,select "Parameter-Display-
  45.         From-Address"and enter $BFEC00.Next select "Parameter-Display-Hex
  46.         -Dump"to display the memory.(To use the SEKA assembler or a similar
  47.         monitor program,enter "q $bfec00".)
  48.         Yoy'll see a byte-wise listing of the addresses starting at
  49.         $BFEC00 in which two bytes always repeat.These two bytes represent
  50.         the status of the two hardware registers.
  51.         The mirroring occurs because not all the address bits are used in
  52.         decoding the address.In addressing this register,only the upper
  53.         two bytes of the address and the low bit,bit 0,are used.The
  54.         address of the two registers goes like this:$BFECxx,where the
  55.         lower address byte xx doesn't contain any information in bits 1-7.
  56.         Only bit 0 contains information about the desired register.You'll
  57.         find this odd form of addressing with most hardware registers.
  58.         Let's look at the information in these registers.Let's look at the
  59.         second register,$BFEC01.Hold down the<ALT>key and select"Parameter
  60.         -Display-HEX-Dump"to redisplay the screen.(SEKA owners must enter
  61.         "q $bfec00"and press the<ALT>key right after pressing the<Return>
  62.         key.)You'll see that contents of every two bytes($BFEC01,$BFEC03,
  63.         etc...)have been changed to $37.This is the status of the special
  64.         keys.This is also true for the other special keys.The following
  65.         keys produce the bytes:
  66.  
  67.             Shift left      $3F
  68.             Shift right     $3D
  69.             Control         $39
  70.             Alternate       $37
  71.             Amiga left      $33
  72.             Amiga right     $31
  73.  
  74.         You can use this register to have a machine language program check
  75.         if one of these keys was pressed and then respond by calling or
  76.         ending a function.A program section might look like this:
  77.  
  78.         skeys=$bfec01
  79.               ...
  80.               cmp.b   #$37,skeys   ;Alternate pressed?
  81.               beq     function1    ;Yes!
  82.               cmp.b   #$31,skeys   ;or right Amiga?
  83.               beq     function2    ;Yes!
  84.               ...                  ;and so on...
  85.  
  86.       5.2.Timing.
  87.       ----------
  88.         If you want to find out how much time elapsed between two events,
  89.         you can use a hardware register to keep track of time quickly and
  90.         precisely.The Amiga contains just such a timekeeper:the I/O port
  91.         componant.The chip has a 24 bit wide counter that has a 60 Hertz
  92.         clock.
  93.         These 24 bits can't be read at once,for instance with a MOVE.L
  94.         command,because the register is divided into three bytes.The low 
  95.         byte is at address $BFE801,the middle at $BFE901,and the high byte
  96.         with bits 16-23 at $BFEA01.
  97.         Here's an example of a way to use this register:finding out how
  98.         long a subroutine takes to run.
  99.  
  100.         test:
  101.                bsr     gettime     ;put current time in D7
  102.                move.l  d7,d6       ;save it in D6
  103.                bsr     routine     ;routine to be timed
  104.                bsr     gettime     ;get the time again
  105.                sub.l   d6,d7       ;elapsed time in
  106.                ...                 ;1/50 seconds in D7!
  107.                nop                 ;set break point here to stop
  108.  
  109.         routine:                   ;test routine
  110.                move    #500,d0     ;delay counter
  111.           
  112.         loop:
  113.                dbra    d0,loop     ;count down
  114.                rts
  115.  
  116.         gettime:
  117.                move.b  $bfea01,d7  ;hi-byte in D0
  118.                lsl.l   #4,d7       ;shift twice by 4 bits
  119.                lsl.l   #4,d7       ;(8 bits shifted)
  120.                move.b  $bfe901,d7  ;get mid-byte
  121.                lsl.l   #4,d7       
  122.                lsl.l   #4,d7       ;shift again
  123.                move.b  $bfe801,d7  ;get the lo-byte
  124.                rts                 ;done
  125.          
  126.       5.3.Reading The Mouse-Joystick.
  127.       -------------------------------
  128.         There are two hardware registers for the mouse and the joystick.
  129.         They contain the state(or the position)of these input devices.Its
  130.         interesting that the same port is used with both the mouse and the
  131.         joystick even through they work completely different.
  132.         The joystick as four switches that are closed during movement and
  133.         give off a potential(-)that is related to the movement of the
  134.         joystick/mouse.The mouses movements give off lots of quick signals
  135.         -two for horizontal and two for vertical movements.
  136.         The computor must keep an eye on the ports so that it can evaluate
  137.         the signals and calculate the new mouse position.This isn't the
  138.         work of the processor though;it already has too much to do.
  139.         You find the status of the mouse/joystick port at address $DFF00A
  140.         for port 1 and $DFF00C for port 2.The information in these words
  141.         is for vertical mouse movement in the lower byte and for
  142.         horizontal movement in the upper byte.
  143.         AssemPro owners be careful!Don't read these addresses,because for
  144.         some reason that causes the computor to crash.This looks
  145.         interesting(the screen begins to dance)but you can only recover by
  146.         pressing <RESET>and losing all your data.
  147.         To read this register,lets write a short program:
  148.  
  149.         ;(5.3A) mouse
  150.  
  151.         test:
  152.               jsr     run       ;test subroutine
  153.               jmp     test      ;continue until broken
  154.               nop               ;breakpoint here
  155.  
  156.         joy= $dff00a
  157.          
  158.         run:
  159.               move    joy,d6    ;data item 1 in D6
  160.               move    joy+2,d7  ;data item 2 in D7
  161.               jmp     run       ;rts for SEKA and other
  162.  
  163.               end
  164.  
  165.         If you assemble the program and start breakable in the debugger
  166.         (SEKA-"j run"),D6 and D7 contain the contents of the two registers
  167.         Move the mouse a bit and watch the register contents.
  168.         As you see,the value in D6 is different.If you just move the mouse
  169.         horizontaly,only the upper bytes value is different,if just moved
  170.         vertically only the upper byte is different.
  171.         You are not getting the absolute position of the mouse pointer on
  172.         the screen.You can see that easily by moving the mouse in the
  173.         upper left corner,then reading the value by restarting the program
  174.         and moving the mouse left again.As you can see,the registers
  175.         contents are always relative.
  176.         Change the program as follows:
  177.  
  178.         ;(5.3B)                   mouse difference
  179.  
  180.         test:
  181.               jsr      run        ;test subroutine
  182.               jmp      test       ;continue until broken
  183.               nop                 ;breakpoint here
  184.  
  185.         joy= $dff00a
  186.  
  187.         run:
  188.               move     d7,d6      ;old position in D6
  189.               move     joy,d7     ;new position in D7
  190.               sub      d7,d6      ;difference in D6
  191.               jmp      run        ;rts for SEKA and other
  192.  
  193.               end
  194.  
  195.         Start Breakable(right-Amiga-A)in the AssemPro debugger and watch
  196.         D6,the result is zero or D7.(SEKA owners have to start the program
  197.         two times.The result in D6 is zero.)If you move the mouse,D6
  198.         contains the difference between the old and new positions since
  199.         the start.You'll find the vertical and horizontal positions of the
  200.         mouse relative to the last time you looked.In this way,you can use
  201.         this register to find the relative mouse movement between two
  202.         checks.
  203.         Now to check the joysticks.Put a joystick in port 2 and change the
  204.         address $DFF00A to $DFF00C in the program.Start Breakable in the
  205.         AssemPro debugger and watch D6,the result is zero or D7.(SEKA
  206.         owners have to start the program two times.The result in D6 is
  207.         zero.)
  208.         Move the joystick up.You'll get the value $FF00.One was subtracted
  209.         from the upper byte.Let the joystick loose.This time you get the
  210.         value $100-one is added.You'll get the same effect if you move the
  211.         joystick left-after you let go,one is subtracted.
  212.         The individual movements and their effects on the joystick program
  213.         are:
  214.  
  215.                        UP      $FF00       HI-BYTE -1
  216.                        DOWN    $FFFF       LO-BYTE -1
  217.                        LEFT    $0100       HI-BYTE +1
  218.                        RIGHT   $0001       LO-BYTE +1
  219.  
  220.         These values aren't terribly reliable.If you move the joystick a
  221.         lot and then look at the value,you'll find a crazy value in D6.
  222.         This is because the input driver thinks that a mouse is attached.
  223.         Nevertheless,this is the quickest way to read a joystick.In this
  224.         way,an external device that gives off evaluatable TTL signals can
  225.         be connected to the port and watched by a machine language
  226.         program.
  227.         Now you just need to find out whether the fire button has been
  228.         pressed,and you'll know how to get all the information you need
  229.         from the joystick.The buttons state is in bit 7 of the byte that
  230.         is in memory location $BFE001.If the bit is set,the button was'nt
  231.         pressed.That's true for the joystick connected to port 2.Bit 6 of
  232.         this byte contains the buttons state when the joystick is in port
  233.         1 or the state of the left mouse button.
  234.         Let's stay on port 2.You can test bit 7 to execute a function when
  235.         the joystick button is pressed without any problems.Bit 7 is the
  236.         sign bit.You can use this program segment:
  237.  
  238.              tst.b   $bfe001     ;was fire button 2 hit?
  239.              bpl     fire        ;yes!branch
  240.  
  241.         The TST.B instruction tests the addressed byte and sets the Z and
  242.         the N flag.If the N flag is set,you know that bit 7 of the tested
  243.         byte is set.Since the fire button turns on LO potential,the bit is
  244.         erased when the button is pressed.The N flag works that way with
  245.         the TST command as well.The BPL command in the program above
  246.         branches if the button was pressed.The PL stands for plus and is
  247.         set when the sign bit is cleared.
  248.         Here is the complete program to check the fire button and joystick
  249.         difference:
  250.  
  251.         ;(5.3C) fire button and joy difference
  252.  
  253.         test:
  254.                jsr     run        ;test subroutine
  255.                tst.b   $bfe001    ;was fire button 2 hit?
  256.                bpl     fire       ;yes! branch
  257.                jmp     test       ;continue until broken
  258.  
  259.         joy = $dff00a
  260.         run:
  261.                move    d7,d6      ;old position in D6
  262.                move    joy,d7     ;new position in D7
  263.                sub     d7,d6      ;difference in D6
  264.                jmp     run        ;rts for SEKA and other
  265.  
  266.         fire:
  267.                nop                ;breakpoint here
  268.  
  269.                end
  270.  
  271.       5.4.Tone Production.
  272.       -------------------
  273.         It's fun to make noises and sounds.The Amiga lets you use Audio
  274.         Devices and various I\O structures to play tones,noises and/or
  275.         music pieces in the background.You'll leave this method to C or
  276.         Basic programmers,since you can use short machine language
  277.         programs to directly program the audio hardware.
  278.         The Paula chip has all the capabilities needed for tone production
  279.         This chip can be accessed using the hardware registers of the
  280.         processor.No library of any high level language can do more than
  281.         you can-program the chip.
  282.         How does it work?Since the disk uses Direct Memory Access(DMA)to
  283.         get information,you just need to tell it where to look for the
  284.         tone or tone sequences that you would like played.You also need to
  285.         tell it how to interpret the data.
  286.         Lets start with the easiest case-producing a constant tone.A tone
  287.         like this consists of a single oscillation that is repeated over
  288.         and over.If you make a diagram of the oscillation,you see the wave
  289.         form of the oscillation.There are several standard waves: sine,
  290.         square,triangle and saw tooth.The simplest is the square wave.
  291.         To produce a square wave,you just need to turn the loud speaker on
  292.         and off.The frequency that occurs here is the frequency of the
  293.         tone. 
  294.         You want to produce such a tone using the Amiga.First you need to
  295.         make a table that contains the amplitude of the tone you wish to
  296.         produce.For a square wave,you only need two entries in the table,a
  297.         large and a small value.Since the sound chip in the Amiga has
  298.         amplitude values between -128 and +127,our table looks like this:
  299.  
  300.         soundtab:
  301.                dc.b -100,100
  302.  
  303.         You need to give the address of the table to the sound chip.You
  304.         have four choices,since the Amiga as four sound channels.The
  305.         address of the hardware register in which the table address for
  306.         channel 0 must be written is $DFF0A0;for channel 1 it is $DFF0B0;
  307.         for channel 2 its $DFF0C0;for channel 3 its $DFF0D0.For stereo
  308.         output,channels 0 and 3 control the left loud speaker.Channels 1
  309.         and 2 control the right loud speaker.For example,choose channel 0
  310.         and write the following:
  311.  
  312.                move.l  #soundtab,$DFF0A0   ;address of the table
  313.  
  314.         Next you need to tell the sound chip how many items there are in
  315.         the table.The data is read from beginning to end and sent to the
  316.         loud speaker.Once it reaches the end,it starts over at the
  317.         beginning.Since the sound chip gets this one word at a time,even
  318.         though the data is in bytes,the table must always have an even
  319.         number of bytes.The length that you give it is the number of words
  320.         the number of bytes/2.
  321.         You put the length for channel 0 in the register at address
  322.         $DFF0A4(for channel x just add x*$10!):
  323.  
  324.                move  #1,$dff0a4   ;length of table in words
  325.  
  326.         Now you have to tell it how quickly to read the data and output it
  327.         to the loud speaker.This word determines the frequency.However,it
  328.         does this "backwards".The larger the value,the lower the frequency
  329.         Choose the value 600 for this example:
  330.  
  331.                move  #600,$dff0a6   ;read in rate
  332.  
  333.         Now you need to decide the loudness level for the tone or noise.
  334.         You have 65 different levels to choose from.Lets choose the middle
  335.         value 40 for our example:
  336.  
  337.                move  #40,$dff0a8    ;loudness level
  338.  
  339.         Thats the data that the sound chip needs to produce the tone.
  340.         However nothing happens yet.What next?The chip can't tell if the
  341.         data thats in the registers is valid,so it doesn't know if it
  342.         should use the data.
  343.         You need to work with the DMA control register at address $DFF096
  344.         to let it know.You only need six bits of this word for your
  345.         purposes:
  346.  
  347.         Bit 15 ($8000)  If this bit is set,every bit that is written to
  348.                         this internal register is set.Otherwise the bits
  349.                         are erased.Zero bits aren't affected.This is very
  350.                         useful because this word also contains DMA
  351.                         information for disk operations that should'nt be
  352.                         changed.
  353.  
  354.         Bit 9 ($200)    This bit makes it posible for the chip to access
  355.                         DMA memory.If you want to start playing the tone,
  356.                         you need to set this bit.
  357.  
  358.         Bit 0-3         Turn channel 0-3 on when bits are set.
  359.  
  360.         You'll start your tone by setting bits 15,9 and 0:
  361.  
  362.                move   #$8000+$200+1,$dff096   ;start DMA
  363.  
  364.         Heres an example of tone production-this time with tone using a
  365.         sine wave:
  366.  
  367.         ;**Sound Generation using hardware registers** (5.5A)
  368.  
  369.         ctlw = $dff096              ;DMA control
  370.         cothi = $dff0a0             ;table address HI
  371.         c0tlo = $c0thi+2            ;table address LO
  372.         c0tl = $c0thi+4             ;table length
  373.         c0per = $c0thi+6            ;read in rate
  374.         c0vol = $c0thi+8            ;loudness level
  375.         
  376.         run:                        ;*Produce a simple tone
  377.              move.l  #table,c0thi   ;table beginning
  378.              move    #8,c0tl        ;table length--8 words
  379.              move    #400,c0per     ;read in rate
  380.              move    #40,c0vol      ;loudness level (volume)
  381.              move    #$8201,ctlw    ;DMA/Start sound
  382.              rts
  383.  
  384.         data                        ;>500K place in CHIP memory
  385.         table:                      ;sound table:sine
  386.          dc.b -40,-70,-40,0,40,70,40,0
  387.  
  388.              end
  389.  
  390.         To test this subroutine,use AssemPro to assemble the routine,save
  391.         the program and load it into the debugger.Next set a breakpoint at
  392.         the RTS,to set the breakpoint in AssemPro select the correct
  393.         address with the mouse and press the right-Amiga-B keys.Start the
  394.         program and listen to the tone.You need another routine to turn
  395.         the tone off,turn your sound down for now.
  396.         To turn the tone off,you just need to erase bit 0 of the DMA
  397.         control register.To do this,you just need to write a 0 in bit 15
  398.         and all the set bits in this register are erased.To erase bit 0,
  399.         just write a one to the memory location:bit 15=0=> bit 0 is erased
  400.         Heres a small routine to stop the tone coming from channel 0:
  401.  
  402.         still:                   ;*turn off tone
  403.                move    #1,ctlw   ;turn off channel 1
  404.                rts
  405.  
  406.         Now lets use the routine in a program to produce a short peep tone
  407.         that you culd,for instance,use as a key click:
  408.  
  409.         ;** Producing a Peep Tone **
  410.         ctlw = $dff096                ;DMA control
  411.         c0thi = $dff0a0               ;HI table address
  412.         c0tlo = $c0thi+2              ;LO table address
  413.         c0tl = $c0thi+4               ;table length
  414.         c0per = $c0thi+6              ;read in rate
  415.         c0vol = $c0thi+8              ;volume
  416.  
  417.         beep:                         ;*Produce a short peep tone
  418.                move.l  #table,c0thi   ;table beginning
  419.                move    #8,c0tl        ;table length
  420.                move    #400,c0per     ;read in rate
  421.                move    #65,c0vol      ;volume
  422.                move    #$8201,ctlw    ;Start DMA (sound)
  423.                move.l  #20000,d0      ;delay counter
  424.  
  425.         loop:
  426.                dbra    d0,loop        ;count down
  427.         
  428.         still:
  429.                move    #1,ctlw        ;turn off tone
  430.                rts
  431.  
  432.         table:
  433.                dc.b 40,70,90,100,90,70,40,0,-4,0
  434.                end
  435.  
  436.         You can play upto four tones at the same time in such a way that
  437.         they are independant of each other.The Amiga also offers another
  438.         method of making the sound more interesting:you can modulate the
  439.         tone.
  440.         Lets produce a siren tone.You could do this by figuring out the
  441.         entire sequence and programming it.However,as you can well imagine
  442.         thats a lot of work.
  443.         Its much easier to use two tone channels.Lets use channel 1 for
  444.         the bass tone and channel 0 for its modulation.Channel 0 needs to
  445.         hold the envelope of the siren tone.It needs to give the expanding
  446.         and contracting of the tone at the right speed.
  447.         You then have two ways that you can have channel zero work with
  448.         channel one.You can control the volume via channel 0,the read in
  449.         rate(frequency),or both.For our example,you'll use frequency
  450.         modulation.
  451.  
  452.         Change the program as follows:
  453.  
  454.         ;** Modulated sound generation via hardware registers **
  455.         ctlw = $dff096                   ;DMA control
  456.         adcon = $dff09e                  ;Audio/Disk control
  457.         c0thi = $dff0a0                  ;HI table address
  458.         c0tlo = c0thi+2                  ;LO table address
  459.         c0tl = c0thi+4                   ;table length
  460.         c0per = c0thi+6                  ;read in rate
  461.         c0vol = c0thi+8                  ;volume
  462.  
  463.         run:
  464.                 move.l  #table,c0thi+16  ;table start for channel 1
  465.                 move    #8,c0tl+16       ;table length--8 words
  466.                 move    #300,c0per+16    ;read in rate
  467.                 move    #40,c0vol+16     ;volume
  468.  
  469.                 move.l  #table2,c0thi    ;table start for channel 0
  470.                 move    #8,c0tl          ;table length
  471.                 move    #60000,c0per     ;read in rate
  472.                 move    #30,c0vol        ;volume
  473.  
  474.                 move    #$8010,adcon     ;modulation mode:FM
  475.                 move    #$8203,ctlw      ;start DMA
  476.                 rts
  477.  
  478.         still:                           ;*Turn Off Tone
  479.                 move    #$10,adcon       ;no more modulations
  480.                 move    #3,ctlw          ;turn off channels
  481.                 rts
  482.  
  483.         table:                           ;data for basic tone
  484.          dc.b -40,-70,-90,-100,-90,-70,-40,0
  485.          dc.b 40,70,90,100,90,70,40,0
  486.  
  487.         table2:                          ;data for modulation
  488.          dc.w 400,430,470,500,530,500,470,430
  489.  
  490.                 end
  491.  
  492.         When you start the program,you'll here a siren.You can change this
  493.         tone to your hearts content.
  494.         Did you notice the added "adcon"register.This register controls
  495.         the modulation of the audio channel as well as handling disk
  496.         functions.The same technique is used here as for the DMA control
  497.         register,bits can only be set if bit 15 is.As a result,you don't
  498.         have to worry about the disk bits.I'd recommend against
  499.         experimentation.
  500.         Control bit 15 isn't the only one of interest to you.You can also 
  501.         use bits 0-7,because they determine which audio channel modulates
  502.         another channel.There is a restriction,though.A channel can only
  503.         modulate the next higher numbered channel.For this reason you use
  504.         channel 1 for the basic tone and channel 0 for the modulation in
  505.         the example.You can't for example,modulate channel three with
  506.         channel zero.Channel 3 can't be used to modulate any other
  507.         channel.
  508.  
  509.         Here is an overview of bits 0-7 of the "adcon"register.
  510.  
  511.         Bit       Function
  512.         -----------------------------------------------------------------
  513.          0        Channel 0 modulates the volume of channel 1
  514.          1        Channel 1 modulates the volume of channel 2
  515.          2        Channel 2 modulates the volume of channel 3
  516.          3        Turn of channel 3
  517.          4        Channel 0 modulates the frequency of channel 1
  518.          5        Channel 1 modulates the frequency of channel 2
  519.          6        Channel 2 modulates the frequency of channel 3
  520.          7        Turn off channel 3
  521.  
  522.         In the example,you set bit 4,which put channel 0 in charge of
  523.         channel one's frequency modulations.
  524.         When you've chosen a channel for use in modulating another channel
  525.         some of the parameters of the channel change.You don't need to
  526.         give volume for this channel,so you can omit it.Now the tables
  527.         data is looked at as words instead of as bytes.These words are
  528.         read into the register of the modulated register at a
  529.         predetermined rate.The Read in Rate Register determines the rate.
  530.         If you want to modulate the frequency and the volume of another
  531.         channel,(In the example,set bits 0 and 4 of "adcon"),the data is
  532.         interpreted a little differently.The first word in the table is
  533.         the volume,the second is the read in rate,and so on.It alternates
  534.         back and forth.In this way,you can for instance,produce the siren
  535.         tone.
  536.  
  537.       5.5.Hardware Registers Overview.
  538.       -------------------------------
  539.         The following tables should give you an overview of the most
  540.         important hardware registers.Theres not enough room to describe
  541.         each register,so I'd recommend getting a hold of the appropriate
  542.         literature.If you experiment with these registers,you should keep
  543.         in mind that this can cause the computor to crash.Save your data
  544.         to disk and then take the disk out of the drive,because you might
  545.         cause the disk drive to execute some wierd functions.
  546.         Lets start with the PIA's.This covers the PIA type 8520.You should
  547.         keep in mind that some functions and connection of the 8520 are
  548.         integrated into the Amiga and so there are limitations on what you
  549.         can do with the PIA's.
  550.  
  551.         PIA A       PIA B       Registers Meaning
  552.         ------------------------------------------------------------------
  553.         BFE001      BFE000      Data register A
  554.         BFE101      BFE100      Data register B
  555.         BFE201      BFE200      Data direction register A
  556.         BFE301      BFE300      Data direction register B
  557.         BFE401      BFE400      Timer A LO
  558.         BFE501      BFE500      Timer A HI
  559.         BFE601      BFE600      Timer B LO
  560.         BFE701      BFE700      Timer B HI
  561.         BFE801      BFE800      Event register Bits 0-7
  562.         BFE901      BFE900      Event register Bits 8-15
  563.         BFEA01      BFEA00      Event register Bits 16-23
  564.         BFEB01      BFEB00      Unused
  565.         BFEC01      BFEC00      Serial data register
  566.         BFED01      BFED00      Interrupt control register
  567.         BFEE01      BFEE00      Control register A
  568.         BFEF01      BFEF00      Control register B
  569.  
  570.         Some internal meanings:
  571.  
  572.         $BFE101    Data register for parallel interface
  573.         $BFE301    Data direction register for the parallel interface
  574.         $BFEC01    State of the keyboard,contains the last special key
  575.                    pressed(Shift,Alternate,Control,Amiga)
  576.  
  577.         Now come the registers that are used for tone production.The first
  578.         two registers should be treated especially carefully-if they are
  579.         used wrong,very nasty effects can occur.
  580.         These registers can be either read or written only.This
  581.         information is included under R/W in the table.
  582.  
  583.         Address       R/W    Meaning
  584.         ------------------------------------------------------------------
  585.         DFF096         W     Write DMA Control
  586.         DFF002         R     Read DMA Control and Blitter Status
  587.         --Audio Channel 0--
  588.         DFF0AA         W     Data register
  589.         DFF0A0         W     Pointer to table beginning Bits 16-18
  590.         DFF0A2         W     Pointer to table beginning Bits 0-15
  591.         DFF0A4         W     Table length
  592.         DFF0A6         W     Read in Rate
  593.         DFF0A8         W     Volume
  594.         --Audio Channel 1--
  595.         DFF0BA         W     Data register
  596.         DFF0B0         W     Pointer to table beginning Bits 16-18
  597.         DFF0B2         W     Pointer to table beginning Bits 0-15
  598.         DFF0B4         W     Table length
  599.         DFF0B6         W     Read in Rate
  600.         DFF0B8         W     Volume
  601.         --Audio Channel 3--
  602.         DFF0CA         W     Data register
  603.         DFF0C0         W     Pointer to table beginning Bits 16-18
  604.         DFF0C2         W     Pointer to table beginning Bits 0-15
  605.         DFF0C4         W     Table length
  606.         DFF0C6         W     Read in Rate
  607.         DFF0C8         W     Volume
  608.         --Audio Channel 4--
  609.         DFF0DA         W     Data register
  610.         DFF0D0         W     Pointer to table beginning Bits 16-18
  611.         DFF0D2         W     Pointer to table beginning Bits 0-15
  612.         DFF0D4         W     Table length
  613.         DFF0D6         W     Read in Rate
  614.         DFF0D8         W     Volume
  615.  
  616.         Now for the registers that contain information about the joystick,
  617.         mouse or potentiometer.These addresses have been gone over in part
  618.         previously.
  619.  
  620.         Address       R/W    Meaning
  621.         ------------------------------------------------------------------
  622.         DFF00A         R     Joystick/Mouse Port 1
  623.         DFF00C         R     Joystick/Mouse Port 2
  624.         DFF012         R     Potentiometer pair 1 Counter
  625.         DFF014         R     Potentiometer pair 2 Counter
  626.         DFF018         R     Potentiometer connection
  627.         DFF034         W     Potentiometer port direction
  628.          
  629.  
  630.  
  631.  
  632.       Chapter 6
  633.       ---------
  634.       6.The Operating System.
  635.       -----------------------
  636.         Now lets take a step forward in your ability to write assembly
  637.         language programs.Its not enough to put a piece of text in memory 
  638.         someplace.You want to be able to put it on the screen.Do you know
  639.         how to write a character on the screen?Do you know how to draw a
  640.         window on the screen that can be modified by the mouse?Actually
  641.         you don't have to have terribly precise knowledge about such
  642.         topics.
  643.         Fortunately,the Amigas operating system supplies routines that
  644.         take care of common tasks like this.It can seem quite complicated
  645.         due to the number of routines necessary.These routines are in
  646.         libraries.We'll look at the libraries in some depth now.
  647.  
  648.       6.1.Load Libraries.
  649.       -------------------
  650.         Before you can use a library,it must be available.It has to be
  651.         loaded into memory.Unfortunately,the whole library must be loaded,
  652.         even if you only need one of the functions.
  653.         First you need to decide what the program must be able to do,so
  654.         you can see which libraries you'll need.For simple I/O text,you
  655.         don't need a library that contains routines for moving graphics!
  656.         There are a number of libraries onj a normal Workbench disk.Heres
  657.         an overview of the names and the sort of functions they do:
  658.    
  659.       Exec.Library;
  660.         This library is needed to load the other libraries.It is already
  661.         in memory and doesn't need to be loaded.Its in charge of basic
  662.         functions like reserving memory and working with I/O channels.
  663.   
  664.       Dos.Library;
  665.         Contains all the functions for normal I/O operations,for instance
  666.         screen or disk access.
  667.   
  668.    
  669.       Intuition.Library;
  670.         Used for working with screens,windows,menus,etc...
  671.    
  672.       Clist.Library;
  673.         This contains routines for working with the Copper lists that are
  674.         used for controlling the screen.
  675.      
  676.       Console.Library;
  677.         Contains graphics routines for text output in console windows.
  678.    
  679.       Diskfont.Library;
  680.         Used for working with the character fonts that are stored on the
  681.         disk.
  682.      
  683.       Graphics.Library;
  684.         This library contains functions to control the Blitter(or graphics
  685.         )chip.Its used for basic graphics functions.
  686.  
  687.       Icon.Library;
  688.         Used in the development and use of workbench symbols(icons).
  689.  
  690.       Layers.Library;
  691.         Used for working with screen memory (layers).
  692.  
  693.       Mathffp.Library;
  694.         Contains basic math floating point operations.
  695.  
  696.       Mathieeedoubbas.Library;
  697.         Contains basic math functions for integers.
  698.  
  699.       Mathtrans.Library;
  700.         Contains higher level mathmatical functions.
  701.  
  702.       Potgo.Library;
  703.         Used for evaluating analog input to the Amiga.
  704.  
  705.       Timer.Library;
  706.         Contains routines for time critical programs.They can be used to
  707.         program exact time intervals.
  708.  
  709.       Translator.Library;
  710.         Contains the single function "Translate",that translates normal
  711.         text written phonetically for the narrator,the speech synthesisor.
  712.  
  713.         You can open(load)all these libraries of course.You should
  714.         remember that this takes time and memory.For this reason,you
  715.         should always think about which functions you need and which
  716.         libraries they are in.
  717.         For example,lets say you want to write a program that does text
  718.         input/output.You need the "Dos.Library",so it can be loaded.
  719.         The "exec.library"is in charge of loading.This library contains
  720.         the OpenLib function that can be called once you've passed the
  721.         needed parameters.AssemPro Amiga includes all the libraries
  722.         necessary for the Amiga,it also includes files that contain the 
  723.         offsets for the operating system calls.The macros contained in
  724.         AssemPro ease assembly language programming considerably.To make
  725.         the programs in this book useful to the largest audience the
  726.         following examples are written for generic assemblers and do not
  727.         include AssemPro's macros.We have used the AssemPro ILABEL and the
  728.         macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the
  729.         programs from the desktop.(If you are using a different assembler
  730.         check your documentation for instructions on linking programs).
  731.  
  732.       6.2.Calling Functions.
  733.       ----------------------
  734.         Since this chapter is rather complex we'll first describe the
  735.         fundamental routines necessary to use the Amiga's operating system
  736.         after a description a complete program is listed.Every library
  737.         begins in memory with a number of JMP commands.These JMPs branch
  738.         to the routines that are in the library.To call a function,you
  739.         need to find the beginning of this JMP table and call function x
  740.         by going to the xth JMP command.Usually you use an offset to get
  741.         to the right JMP command.Normally,you don't start at the beginning
  742.         but at the end of the JMP table,so use negative offsets.
  743.         It works out very easily.Now lets open the "dos.library"by using
  744.         "exec.library's"base address.This address is $000004.To call a
  745.         fuction from another library,you need to use another base address.
  746.         Now you need the offset for the function that you want.You want
  747.         the OpenLib function that has -408 as an offset.You'll find a list
  748.         of function offsets in the appendix.
  749.         You need a pointer to the name of the library you are loading for
  750.         the OpenLib function(in this case "dos.library")and a long word in
  751.         memory that you can use to store the base address of the DOS
  752.         library.You get this back from the OpenLib function.You need to be
  753.         sure to write the library name in lower case letters(dos.library),
  754.         otherwise you can't open it.I entered a name in capitol letters
  755.         once and spent a lot of time finding this error.
  756.  
  757.         The routine looks like this:
  758.  
  759.         ;** Load the DOS library 'dos.library' (6.2A) **
  760.         Execbase = 4                    ;base address of the EXEC library
  761.         OpenLib  = -408                 ;offset for the OpenLib function
  762.  
  763.         IoErr    = -132                 ;offset for IoErr information
  764.  
  765.         init:
  766.                move.l  Execbase,a6      ;base address in A6
  767.                lea     dosname,a1       ;address of library name
  768.                moveq   #0,d0            ;version number
  769.                jsr     OpenLib(a6)      ;open DOS library
  770.                move.l  d0,dosbase       ;save DOS base address
  771.                beq     error            ;if zero,then error!
  772.                ...                      ;your program goes here
  773.                ...                      ;more program...
  774.  
  775.  
  776.         error:                          ;error
  777.                move.l  dosbase,a6       ;address of library name
  778.                jsr     IoErr(a6)        ;call IoErr for error info
  779.                move.l  d0,d5            
  780.                ...                      ;your error routine goes here
  781.                rts
  782.  
  783.  
  784.         dosname:                        ;name of library to open
  785.                dc.b    'dos.library',0,0
  786.                align                    ;SEKA uses-even
  787.  
  788.         dosbase:                        ;storage for DOS base address
  789.                blk.l   1
  790.  
  791.                end
  792.  
  793.         This is the way to load the DOS library so that you can use it.All
  794.         library functions are called this way.Parameters are put in
  795.         registers and passed to the function.When there is an error,when
  796.         the function doesn't run correctly,a zero is usually put in data
  797.         register D0.
  798.         Once your program is done with its work,you need to close the
  799.         libraries that are still open before you return to the CLI or 
  800.         Workbench.The CloseLib function (offset -414)takes care of this
  801.         job.This function is in the EXEC library just like the OpenLib.The
  802.         only parameter it needs is the base address of the library that is
  803.         closed.To close "dos.library",do the following:
  804.  
  805.         CloseLib = -414               ; (6.2B)
  806.                ...
  807.                move.l  Execbase,a6    ;EXEC base address
  808.                move.l  dosbase,a1     ;DOS base address
  809.                jsr     CloseLib(a6)   ;close library
  810.  
  811.       6.3.Program Initialization.
  812.       ---------------------------
  813.         Before you can start a program,you need to initialize many things
  814.         so that the program can run.
  815.         Lets take an example program that does some text editing.A program
  816.         like this must be able to store text,so it needs to be able to
  817.         access memory.It also needs to be able to accept keyboard input
  818.         and do screen output,so it needs an output window.
  819.         To do this,you need to open one or more of the libraries that we
  820.         talked about earlier.Lets assume that you've loaded the DOS
  821.         library,so that you can do the next steps.
  822.  
  823.       6.3.1.Reserve Memory.
  824.       ---------------------
  825.         There are several ways to get the operating system to assign you a
  826.         chunk of memory.You need to use one of them,so that during multi-
  827.         tasking,you don't have one program overwriting another programs
  828.         memory area.
  829.         Lets look at the function that is normally used.This function is
  830.         in the resident EXEC library and has the name AllocMem (offset
  831.         -$c6).It reserves a memory area,using the value in D0 as the
  832.         length.The address that the memory area begins at is returned in
  833.         the D0 data register.If it returns zero,the program could'nt give
  834.         you that much memory.
  835.         You can also use a mode word in D1 to determine whether the memory
  836.         area that is reserved should be erased or not.
  837.         The routine looks like this:
  838.  
  839.         ExecBase = 4                  ; (6.3.1A)
  840.         AllocMem = -$c6
  841.                ...
  842.                move.l  #number,d0     ;number of bytes to reserve
  843.                move    #mode,a6       ;mode word
  844.                move.l  ExecBase,a6    ;DOS base address in A6
  845.                jsr     AllocMem(a6)   ;call function
  846.                move.l  d0,address     ;save memory's start address
  847.                beq     error          ;memory not reserved
  848.                ...
  849.  
  850.         The second way to reserve memory is to use the AllocAbs function
  851.         (offset -$CC).This function in contrast to the AllocMem function
  852.         reserves a particular memory area.The D0 register contains the
  853.         number of bytes that should be reserved.Address register A1
  854.         contains the desired start address.This function returns a zero in
  855.         D0 if the memory area can't be reserved.
  856.  
  857.         ExecBase = 4                  ; (6.3.1B)
  858.         AllocAbs = -$cc
  859.                ...
  860.                move.l  #number,d0     ;number of bytes to reserve
  861.                lea     address,a1     ;desired start address
  862.                move.l  execbase,a6    ;EXEC base address
  863.                jsr     AllocAbs(a6)   ;reserve memory
  864.                tst.l   d0             ;everything ok?
  865.                beq     error          ;no!
  866.                ...
  867.  
  868.         When the program has done its work and must return to the CLI or
  869.         the Workbench,it needs to return the memory it as reserved to the
  870.         system.The FreeMem function (offset -$D2) handles this.
  871.         The function works like AllocAbs in that the number of bytes is
  872.         put in D0 and the start address of the memory area is put in A1.
  873.         If you try to free up a memory area that was'nt reserved,you'll
  874.         usually crash the computor.
  875.         The routine to free up a memory area looks like this:
  876.  
  877.         ExexBase = 4                  ; (6.3.1C)
  878.         FreeMem = -$d2
  879.                ...
  880.                move.l  #number,d0     ;number of bytes released
  881.                lea     address,a1     ;start address from AllocAbs
  882.                move.l  ExecBase,a6    ;ExecBase address
  883.                jsr     FreeMem(a6)    ;free up memory
  884.                tst.l   d0             ;everything ok?
  885.                beq     error          ;no!
  886.                ...
  887.  
  888.       6.3.2.Opening a Simple Window.
  889.       ------------------------------
  890.         The title of this chapter may sound a bit strange.However,the
  891.         differences between the two different methods of opening a window
  892.         are so great that they should be handled in seperate chapters.
  893.         The method of opening a window presented here is very simple,but
  894.         it doesn't allow you to work with all the gadgets.These gadgets
  895.         include the close symbol in the upper left corner of a window and
  896.         the size symbol in the lower left corner.
  897.         If you open the window in the simple manner,almost all the gadgets
  898.         are present.However,the close symbol is not.As a result,this
  899.         method isn't appropriate for every application.Now lets look at
  900.         the method.
  901.         To open a window,use a function from the DOS library,so you need
  902.         to open the library first (see the section "Load Library").This
  903.         open function is an all purpose function that can be used for many
  904.         things.For this reason,it makes good sense to put a "open"
  905.         subroutine in your program.You can use it a lot.Lets do the basic
  906.         steps:
  907.  
  908.         ;** Load the DOS Library 'dos.library'  (6.3.2A) **
  909.         ExecBase = 4                   ;base addres of the EXEC library
  910.         OpenLib = -408                 ;offset of OpenLib function
  911.         Open = -30                     ;Offset of the DOS function OPEN
  912.  
  913.         init:
  914.                move.l  ExecBase,a6     ;base address in A6
  915.                lea     dosname(pc),a1  ;address of library name
  916.                move.q  #0,d0           ;version number:unimportant
  917.                jsr     OpenLib(a6)     ;call the function
  918.                move.l  d0,dosbase      ;save DOS base address
  919.                beq     error           ;if zero,then error!
  920.                ...                     ;more of your program
  921.                ...                     ;now open window,etc...
  922.  
  923.  
  924.         error:
  925.                ...                     ;error occured
  926.                ...                     ;your error routine
  927.  
  928.  
  929.         openfile:                      ;general open function
  930.                move.l  dosbase,a6      ;DOS base address in A6
  931.                jsr     Open(a6)        ;call OPEN function
  932.                tst.l   d0              ;test if ok
  933.                rts                     ;done,evaluate test later
  934.  
  935.         dosname:                       ;name of library to be opened
  936.                dc.b    'dos.library',0,0
  937.                align                   ;even
  938.  
  939.         dosbase:                       ;spot for DOS base address
  940.                blk.l   1
  941.  
  942.         You call the Openfile routine,because the label "Open"is already
  943.         being used for the offset.This routine calls the Open function
  944.         that is in the DOS library.
  945.         This isn't everything.The function must be given some parameters
  946.         so that it knows what to open.The parameters are sent in registers
  947.         D1 and D2.D1 points to a definition block what specifies what
  948.         should be opened.You need to have a filename ended with a null
  949.         byte there.D1 must be passed as a long word like all addresses.D2
  950.         contains the mode that the function should run in.There is an old
  951.         (1005) and a new (1006) mode.This number must be passed in D2's
  952.         long word.
  953.         Heres an overview of how windows are opened.Fortunately,AmigaDos
  954.         allows you to use input and output channels in the same way.The
  955.         standard channels are disk files,the console (keyboard and screen)
  956.         the printer interface and the serial RS232 interface.
  957.         The console input/output is what you'll work with now.When you
  958.         specify the console as the filename of the channel to be opened,a
  959.         window is opened automatically.
  960.         The name must begin with CON:to do this.Its similar to DF0:for
  961.         disk operations.A little more infotmation about the window is
  962.         still needed.
  963.         You need to specify the X and Y coordinates of the upper left and
  964.         lower right corners of the window as well as the name that should
  965.         appear in the title line of the window.A complete definition block
  966.         for a window like this would appear like the following line:
  967.  
  968.               consolname: dc.b 'CON:0/100/640/100/**Window**',0
  969.  
  970.         To open this window,the line above needs to be inserted in the
  971.         following program:
  972.  
  973.         mode_old = 1005
  974.  
  975.         lea     consolname(pc),a1    ;consol definition
  976.         move.l  #mode_old,d0         ;mode
  977.         bsr     openfile             ;console open
  978.         beq     error                ;didn't work
  979.         move.l  d0,conhandle
  980.  
  981.         rts
  982.                 ...
  983.         conhandle:   dc.l 1          ;space for handle
  984.  
  985.         There are two points to clear up yet.
  986.         You should use mode_old as the the mode when you open a window.
  987.         Logically the window doesn't exist before opening so this seems
  988.         wierd but it doesn't hurt anything.
  989.         The parameter that returns from "openfile"in D0 is zero in the
  990.         case of an error,in the case that opening didn't work.Otherwise
  991.         the value is the identification number (handle number) of the
  992.         opened channel.You need to store it away,because every function
  993.         that wants to use this channel must give the handle number.In the
  994.         example,you stored this number in the "conhandle"long word.
  995.         As mentioned,the window you've opened doesn't have a close symbol
  996.         but it can be made bigger and smaller and moved forward and back.
  997.         The manipulations that are carried out using the mouse are
  998.         completely taken care of by the Amiga (in contrast to the ATARI ST
  999.         where the programmer has to take care of these things).
  1000.         An important function that uses the handle number is the one that
  1001.         closes the channel (in your case the window).This function is also
  1002.         in the DOS library and is called "Close".Its offset is -36 and it
  1003.         only needs one parameter;the handle number of the channel that is
  1004.         closed must be in the D1 register.
  1005.         After your work is done,you need to put the following lines in
  1006.         your program to close the window:
  1007.  
  1008.         Close = -36                    ; (6.3.2C)
  1009.                 ...
  1010.                 move.l  conhandle,d1   ;handle number in D1
  1011.                 move.l  dosbase,a6     ;DOS base address in A6
  1012.                 jsr     Close(a6)      ;close channel!
  1013.  
  1014.         The window disappears!
  1015.  
  1016.         Now for a few remarks about opening and closing the window in this
  1017.         way.If you open several windows in the same way,you'll get several
  1018.         windows and thus several handle numbers.In this way,you can put as
  1019.         many windows on the screen as you like.You can do your work with
  1020.         them and close them individually.
  1021.         Here is the complete program to open and close a simple window in
  1022.         AssemPro format (We have used the AssemPro ILABEL and the macros
  1023.         INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the program
  1024.         from desktop.If you are using a different assembler check your
  1025.         documentation for instructions on starting and exiting programs):
  1026.  
  1027.         ;***** 6.3.2 S.D *****
  1028.  
  1029.         OpenLib        =-30-378
  1030.         closelib       =-414
  1031.         ;execbase      =4                 ;defined in AssemPro macros
  1032.  
  1033.  
  1034.         *calls to Amiga DOS:
  1035.  
  1036.         open           =-30
  1037.         close          =-30-6
  1038.         IoErr          =-132
  1039.         mode_old       = 1005
  1040.         alloc_abs      =-$cc
  1041.  
  1042.         ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
  1043.  
  1044.         INIT_AMIGA                        ;AssemPro only
  1045.  
  1046.         run:
  1047.                bsr     init               ;initialization
  1048.                bra     test               ;system-test
  1049.  
  1050.         init:                             ;system initialization and open
  1051.                move.l  execbase,a6        ;number of execute-library
  1052.                lea     dosname(pc),a1     
  1053.                moveq   #0,d0
  1054.                jsr     openlib(a6)        ;open DOS-Library
  1055.                move.l  d0,dosbase
  1056.                beq     error
  1057.  
  1058.                lea     consolname(pc),a1  ;consol definition
  1059.                move.l  #mode_old,d0
  1060.                bsr     openfile           ;consol open
  1061.                beq     error
  1062.                move.l  d0,conhandle
  1063.  
  1064.                rts
  1065.  
  1066.         test:
  1067.  
  1068.               bra qu                      ;quit and exit
  1069.  
  1070.  
  1071.         error:
  1072.               move.l  dosbase,a6
  1073.               jsr     IoErr(a6)
  1074.               move.l  d0,d5
  1075.  
  1076.               move.l  #-1,d7              ;flag
  1077.  
  1078.         qu:
  1079.               move.l  conhandle,d1        ;window close
  1080.               move.l  dosbase,a6
  1081.               jsr     close(a6)
  1082.               move.l  dosbase,a1          ;DOS.Lib close
  1083.               move.l  execbase,a6
  1084.               jsr     closelib(a6)
  1085.  
  1086.               EXIT_AMIGA                  ;AssemPro only
  1087.  
  1088.         openfile:                         ;open file
  1089.               move.l  a1,d1               ;pointer to I/O-Definition-Text
  1090.               move.l  d0,d2
  1091.               move.l  dosbase,a6
  1092.               jsr     open(a6)
  1093.               tst.l   d0
  1094.               rts
  1095.  
  1096.         dosname: dc.b 'dos.library',0,0
  1097.               Align.w
  1098.         
  1099.         dosbase: dc.l 0
  1100.  
  1101.         consolname: dc.b 'CON:0/100/640/100/**CLI-Test**',0
  1102.               Align.w
  1103.  
  1104.         conhandle: dc.l 0
  1105.  
  1106.  
  1107.               end
  1108.  
  1109.         There is another way to open a window easily.Just use RAW:instead
  1110.         of CON:as the channel designator.All the other parameters and
  1111.         operations remain the same.
  1112.         If you try them both out,you won't see any differences between the
  1113.         two windows.They both look the same and can be worked with in the 
  1114.         same way with the mouse.The difference comes when you input to the
  1115.         window.In the RAW:window,the cursor keys are ignored.In the CON:
  1116.         window and in CLI,they do work.
  1117.  
  1118.       6.4.Input/Output.
  1119.       -----------------
  1120.         Besides managing and making calculations with data,the most
  1121.         important work of a program is to input and output the data.There
  1122.         are many methods of data transfer in and out of the computor,for
  1123.         instance screen or printer output,keyboard input,using the serial
  1124.         or the parallel interface,tone or speech output and finally disk
  1125.         operations.
  1126.         You want to learn about all these methods of data input and output
  1127.         for programming and applications.We've written some programs as
  1128.         subroutines that should be useful for later programs.It makes good
  1129.         sense to make a library of these subroutines that can either be
  1130.         directly integrated in a new program or linked to a program.At the
  1131.         end of the sections there is a list of a complete program so you
  1132.         can see how the subroutines are used.
  1133.         To prepare for input/output,you need to have data to output and
  1134.         space to input data.To get this ready,you need a correct program
  1135.         beginning in which the EXEC and DOS libraries are opened and
  1136.         memory is reserved.After this,you begin most programs by outputing
  1137.         some text.The text can be a program title or the instruction to
  1138.         input data over the keyboard.Lets start looking at screen output.
  1139.  
  1140.       6.4.1.Screen Output.
  1141.       --------------------
  1142.         For a computor like the Amiga the first question is where should
  1143.         the screen output be sent?The answer is simple for many computors;
  1144.         they only have one screen,and output goes there.You need to
  1145.         specify which window to write to when you use the Amiga,however.
  1146.  
  1147.         There are two possibilites:
  1148.  
  1149.         1.Output to CLI
  1150.  
  1151.         2.Output to another window
  1152.  
  1153.         The first posibillity only exists if the program that makes the
  1154.         output was started from CLI.If not,you need to open your own
  1155.         custom window for your program.If so,you can use the window that
  1156.         was opened by the CLI for output.
  1157.         If you use the second method,you need to open a window.As you've
  1158.         already seen,there are three methods.For simple text and character
  1159.         output,the difference between the three sorts of windows isn't
  1160.         very great.Here you have a free hand in determining which sort of
  1161.         window to use.Lets open a CON:window and put its handle number in
  1162.         "conhandle".
  1163.         You've opened your window and want to output a title.You choose
  1164.         text to output and then put it in memory using a code segment like
  1165.         this:
  1166.  
  1167.               title: dc.b "** Welcome to this Program! **"
  1168.               titleend:
  1169.               align              ;even
  1170.  
  1171.         The "align"(even) is a pseudo-op that should follow text when it
  1172.         is followed by either word data or program lines.It causes the
  1173.         assembler to insert a null byte if necessary to make the address
  1174.         even.
  1175.         To output this text you need another DOS function:Write.This has
  1176.         an offset of -48 and needs three parameters:
  1177.  
  1178.         In D1   the handle of an opened output channel that should be
  1179.                 written to (in your case,this is the handle number that
  1180.                 you go back from the Open command when you opened your
  1181.                 window.).
  1182.         In D2   the address of the text to be output (in the example,the
  1183.                 address "title").
  1184.         In D3   the number of characters to be output in bytes.
  1185.  
  1186.         To find the number of bytes to output,you need to count the number
  1187.         of characters in your text.Use "titleend"to calculate this.Using
  1188.         this label,the assembler can calculate the length of your text for
  1189.         itself (after all,why should you count when you have a computor?) 
  1190.         if you write:
  1191.  
  1192.              move.l  #titleend-title,d3
  1193.  
  1194.         The advantage of specifying the length is that you can put control
  1195.         characters between the beginning and end of the text.In this way,
  1196.         you can execute certain functions using text output.You'll learn
  1197.         about the control characters in a bit.
  1198.  
  1199.         Heres the routine:
  1200.  
  1201.         Write = -48                          ; (6.4.1A)
  1202.                 ...                          ;open window
  1203.                 ...
  1204.                 move.l  dosbase,a6           ;DOS base address
  1205.                 move.l  conhandle,d1         ;pass handle
  1206.                 move.l  #title,d2            ;text address
  1207.                 move.l  #titleend-title,d3   ;and length
  1208.                 jsr     Write(a6)            ;call function
  1209.                 ...
  1210.  
  1211.  
  1212.         title: dc.b "** Welcome to this Program! **"
  1213.          
  1214.         titleend:
  1215.         
  1216.         align                                ;event
  1217.  
  1218.                 end
  1219.  
  1220.         You'll certainly use this function a lot.You'll often want to
  1221.         output just one character though.To allow you to do this and
  1222.         similar text related tasks,there are four subroutines,each of
  1223.         which do a different sort of output:
  1224.  
  1225.       Pmsg;
  1226.         Outputs the text from (D2) to the first null byte.
  1227.  
  1228.       Pline;
  1229.         Is the same as the routine above except that the text is
  1230.         automatically followed by a CR,the cursor is positioned at the
  1231.         beginning of the next line.
  1232.  
  1233.       Pchar;
  1234.         Outputs the character in D0
  1235.  
  1236.       Pcrlf;
  1237.         Puts the cursor at the beginning of the next line.
  1238.  
  1239.         Heres the subroutine package:
  1240.  
  1241.         Write = -48                  ; (6.4.1B)
  1242.                 ...
  1243.  
  1244.         pline:                       ;*output line and then a CR
  1245.                 bsr     pmsg         ;output line
  1246.  
  1247.         pcrlf:
  1248.                 move    #10,d0       ;line feed
  1249.                 bsr     pchar        ;output
  1250.                 move    #13,d0       ;and CR
  1251.  
  1252.         pchar:
  1253.                 move.b  d0,outline   ;character in output buffer
  1254.                 move.l  #outline,d2  ;address of the character
  1255.                  
  1256.         pmsg:                        ;*output line (D2) upto null
  1257.                 move.l  d2,a0        ;address in A0
  1258.                 clr     d3           ;length = 0
  1259.  
  1260.         ploop:
  1261.                 tst.b   (a0)+        ;null byte ?
  1262.                 beq     pmsg2        ;yes:length found
  1263.                 addq.l  #1,d3        ;else length + 1
  1264.                 bra     ploop        ;and continue looking
  1265.  
  1266.         pmsg2:
  1267.                 move.l  dosbase,a6   ;DOS base address in A6
  1268.                 move.l  conhandle,d1 ;our window handle
  1269.                 jsr     Write(a6)    ;call write function
  1270.                 rts                  ;done!
  1271.  
  1272.         outline:        dc.w 0       ;output buffer for 'pchar'
  1273.  
  1274.         conhandle:      dc.l 0       ;windows handle
  1275.  
  1276.         Here is an example program to open and close a simple window and
  1277.         output a text message in AssemPro format (We have used the
  1278.         AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
  1279.         start the program from desktop.If you are using a different
  1280.         assembler check your documentation for instructions on starting
  1281.         and exiting programs.):
  1282.  
  1283.         Here is the complete program in AssemPro format:
  1284.  
  1285.         ;***** 6.4.1C.asm S.D. *****
  1286.  
  1287.         Openlib     =-30-378
  1288.         closelib    =-414
  1289.         ;execbase   = 4                    ;Defined in AssemPro
  1290.                                            ;Macros
  1291.  
  1292.         * calls to Amiga Dos:
  1293.  
  1294.         open        =-30
  1295.         close       =-30-6
  1296.         write       =-48
  1297.         IoErr       =-132
  1298.         mode_old    = 1005
  1299.         alloc_abs   =-$cc
  1300.  
  1301.                ILABEL AssemPro:include/Amiga.l ;AssemPro only
  1302.  
  1303.                INIT_AMIGA                  ;AssemPro only
  1304.  
  1305.         run:
  1306.                bsr     init                ;initialization
  1307.                bsr     test                ;system test
  1308.                nop 
  1309.                bra qu                      ;quit and exit
  1310.  
  1311.         test:
  1312.                move.l  #title,d0
  1313.                bsr     pmsg
  1314.                bsr     pcrlf
  1315.                bsr     pcrlf
  1316.  
  1317.                rts
  1318.  
  1319.         init:                              ;system initialization and
  1320.                                            ;open
  1321.                move.l  execbase,a6         ;number of execute-library
  1322.                lea     dosname(pc),a1
  1323.                moveq   #0,d0
  1324.                jsr     openlib(a6)         ;open DOS-library
  1325.                move.l  d0,dosname
  1326.                beq     error
  1327.  
  1328.                lea     consolname(pc),a1   ;console definition
  1329.                move.l  #mode_old,d0
  1330.                bsr     openfile            ;console open
  1331.                beq     error
  1332.                move.l  d0,conhandle
  1333.  
  1334.                rts
  1335.  
  1336.         pmsg:                              ;print message (D0)
  1337.                movem.l d0-d7/a0-a6,-(sp)
  1338.                move.l  d0,a0
  1339.                move.l  a0,d2
  1340.                clr.l   d3
  1341.  
  1342.         ploop:
  1343.                tst.b   (a0)+
  1344.                beq     pmsg2
  1345.                addq.l  #1,d3
  1346.                bra     ploop               ;length calculate
  1347.  
  1348.         pmsg2:
  1349.                move.l  conhandle,d1
  1350.                move.l  dosbase,a6
  1351.                jsr     write(a6)
  1352.                movem.l (sp)+,d0-d7/a0-a6
  1353.                rts
  1354.  
  1355.         pcrlf:
  1356.                move    #10,d0
  1357.                bsr     pchar
  1358.                move    #13,d0
  1359.  
  1360.         pchar:                             ;output char in D0
  1361.                movem.l d0-d7/a0-a6,-(sp)   ;save all
  1362.                move.l  conhandle,d1
  1363.  
  1364.         pch1:
  1365.                lea     outline,a1
  1366.                move.b  d0,(a1)
  1367.                move.l  a1,d2
  1368.                move.l  #1,d3               ;1 letter
  1369.                move.l  dosbase,a6
  1370.                jsr     write(a6)
  1371.                movem.l (sp)+,d0-d7/a0-a6   ;restore all
  1372.  
  1373.         error:
  1374.                move.l  dosbase,a6
  1375.                jsr     IoErr(a6)
  1376.                move.l  d0,d5
  1377.  
  1378.                move.l  #-1,d7              ;flag
  1379.  
  1380.         qu:
  1381.                move.l  conhandle,d1        ;window close
  1382.                move.l  dosbase,a6
  1383.                jsr     close(a6)
  1384.  
  1385.                move.l  dosbase,a1          ;DOS.Lib close
  1386.                move.l  execbase,a6
  1387.                jsr     closelib(a6)
  1388.  
  1389.                EXIT_AMIGA                  ;AssemPro only
  1390.  
  1391.         openfile:                          ;open file
  1392.                move.l  a1,d1               ;pointer to I/O-definition-
  1393.                                            ;text
  1394.                move.l  d0,d2
  1395.                move.l  dosbase,a6
  1396.                jsr     open(a6)
  1397.                tst.l   d0
  1398.                rts
  1399.  
  1400.         dosname: dc.b 'dos.library',0,0
  1401.                align.w
  1402.  
  1403.         dosbase: dc.l 0
  1404.  
  1405.         consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0
  1406.                align.w
  1407.  
  1408.         conhandle: dc.l 0
  1409.  
  1410.         title: dc.b '** Welcome to this Program! **'
  1411.  
  1412.         titleend:
  1413.                align
  1414.  
  1415.         outline: dc.w 0                    ;output buffer for char
  1416.  
  1417.                end
  1418.  
  1419.         Using this program,you can very easily put whatever you want in
  1420.         the CON:window.These functions also work in RAW:window.You should
  1421.         rename "conhandle"as "rawhandle",so that you don't get things
  1422.         mixed up later.
  1423.         Lets stay with the CON:window.As mentioned earlier,you can output
  1424.         special characters that execute functions or change parameters for
  1425.         output.These characters are called control characters.
  1426.         You've already learned about one of these control characters,Line
  1427.         Feed ($A).This character isn't just output;instead,it calls a
  1428.         function that moves the cursor into the next line and moves the
  1429.         screen up.This is very useful,but there are much more interesting
  1430.         control characters.
  1431.         Here's a list of control characters that execute functions.These
  1432.         characters are given in hex.
  1433.  
  1434.       Control Sequence;
  1435.  
  1436.         Sequence     Function
  1437.         ------------------------------------------------------------------
  1438.          08          Backspace
  1439.          0A          Line Feed,Cursor down
  1440.          0B          Move Cursor up a line
  1441.          0C          Clear screen
  1442.          0D          Carrige return,cursor in the first column
  1443.          0E          Turn on normal characters (Cancel Of Effects)
  1444.          0F          Turn on special characters
  1445.          1B          Escape
  1446.  
  1447.         The following sequences begin with $9B,the CSI (Control Sequence
  1448.         Introducer).The characters that follow execute a function.The
  1449.         values in square brackets can be left off.The n's you see
  1450.         represent one or more digit decimal numbers given using ASCII
  1451.         characters.The value that is used when n is left off,is given in
  1452.         the parenthesis that follow n in the description of the function
  1453.         in the table.
  1454.  
  1455.       Control Sequence Introducer;
  1456.  
  1457.         Sequence       Function
  1458.         ------------------------------------------------------------------
  1459.         9B[n]40        Insert n blanks
  1460.         9B[n]41        Move cursor n (1) lines up
  1461.         9B[n]42        Move cursor n (1) lines down
  1462.         9B[n]43        Move cursor n (1) characters to the right
  1463.         9B[n]44        Move cursor n (1) characters to the left
  1464.         9B[n]45        Move cursor down n (1) lines into column 1
  1465.         9B[n]46        Move cursor up n (1) lines and into column 1
  1466.         9B[n][3B n]48  Cursor in line;Set column
  1467.         9B 4A          Erase screen from cursor
  1468.         9B 4B          Erase line from the cursor
  1469.         9B 4C          Insert line
  1470.         9B 4D          Delete line
  1471.         9B[n]50        Delete n characters starting at cursor
  1472.         9B[n]53        Move up n lines
  1473.         9B[n]54        Move down n lines
  1474.         9B 32 30 68    Line feed => Line feed + return
  1475.         9B 32 30 6C    Line feed => just Line feed
  1476.         9B 6E          Sends the cursor position!A string of the following
  1477.                        form is returned:
  1478.                        9B (line) 3B (column) 52
  1479.         9B(style);(foreground colour);(Background Colour)6D
  1480.                        The three parameters are decimal numbers in ASCII
  1481.                        format.They mean:
  1482.                        Style:  0 = normal
  1483.                                1 = bold
  1484.                                3 = italic
  1485.                                4 = underline
  1486.                                7 = inverse
  1487.                        Foreground colour: 30-37
  1488.                        Colour 0-7 for Text
  1489.                        Background colour: 40-47
  1490.                        Colour 0-7 for background
  1491.         9B(length)74   sets the maximum number of lines to be displayed
  1492.         9B(width)75    sets the maximum line length
  1493.         9B(distance)78 defines the distance in pixels from the left border
  1494.                        of the window to the place where output should
  1495.                        begin
  1496.         9B(distance)79 defines the distance in pixels from the upper
  1497.                        border of the window to the place where output
  1498.                        should begin
  1499.                        The last four functions yield the normal values if
  1500.                        you leave off the parameters.
  1501.  
  1502.         9B 30 20 70    Make cursor invisible
  1503.         9B 20 70       Make cursor visible
  1504.         9B 71          Sends window construction.A string of the following
  1505.                        form is returned:
  1506.                        9B 31 3B 31 3B (lines) 3B (columns) 73
  1507.  
  1508.         To see how the control characters work,have "pmsg"output this text
  1509.         to your window:
  1510.  
  1511.         mytext: dc.b $9b,"4;31;40m"                ; (6.3.2D)
  1512.                 dc.b "underline"
  1513.                 dc.b $9b,"3;33;40m",$9b,"5;20H"
  1514.                 dc.b "** Hello World! **",0
  1515.  
  1516.         The parameters for the control sequence are put in quotation marks
  1517.         so they are treated as an ASCII string.Now you see,just how easy
  1518.         it is to do text output!
  1519.         Here is the complete program to open and output the text and
  1520.         control codes to your window in AssemPro format (We have used the
  1521.         AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
  1522.         start the programs from desktop.If you are using a different
  1523.         assembler check your documentation for instructions on starting
  1524.         and exiting programs):
  1525.  
  1526.         ; ***** 6.4.1D.ASM S.D. *****
  1527.  
  1528.  
  1529.         openlib    =-30-378
  1530.         closelib   =-414
  1531.         ;execbase  = 4                     ;defined in AssemPro macros
  1532.  
  1533.         * calls to Amiga Dos:
  1534.  
  1535.         open       =-30
  1536.         close      =-30-6
  1537.         write      =-48
  1538.         IoErr      =-132
  1539.         mode_old   = 1005
  1540.         alloc_abs  =-$cc
  1541.  
  1542.                ILABEL AssemPro:includes/Amiga.l   ;AssemPro only
  1543.  
  1544.                INIT_AMIGA                  ;AssemPro only
  1545.  
  1546.         run:
  1547.                bsr     init                ;initialization
  1548.                bsr     test                ;system test
  1549.                nop
  1550.                bra qu                      ;quit and exit
  1551.  
  1552.         test:
  1553.                move.l  #mytext,d0
  1554.                bsr     pmsg
  1555.                bsr     pcrlf
  1556.                bsr     pcrlf
  1557.  
  1558.                rts
  1559.  
  1560.         init:                              ;system initialization and open
  1561.                move.l  execbase,a6         ;number of execute-library
  1562.                lea     dosname(pc),a1
  1563.                moveq   #0,d0
  1564.                jsr     openlib(a6)         ;open DOS-Library
  1565.                move.l  d0,dosbase
  1566.                beq     error
  1567.  
  1568.                lea     consolname(pc),a1   ;console definition
  1569.                move.l  #mode_old,d0
  1570.                bsr     openfile            ;console open
  1571.                beq     error
  1572.                move.l  d0,conhandle
  1573.  
  1574.                rts
  1575.  
  1576.         pmsg:                              ;print message (D0)
  1577.                movem.l d0-d7/a0-a6,-(sp)
  1578.                move.l  d0,a0
  1579.                move.l  a0,d2
  1580.                clr.l   d3
  1581.  
  1582.         ploop: 
  1583.                tst.b   (a0)+
  1584.                beq     pmsg2
  1585.                addq.l  #1,d3
  1586.                bra     ploop
  1587.  
  1588.         pmsg2:
  1589.                move.l  conhandle,d1
  1590.                move.l  dosbase,a6
  1591.                jsr     write(a6)
  1592.                movem.l (sp)+,d0-d7/a0-a6
  1593.                rts
  1594.  
  1595.         pcrlf:
  1596.                move    #10,d0
  1597.                bsr     pchar
  1598.                move    #13,d0
  1599.  
  1600.         pchar:                             ;output char in D0
  1601.                movem.l d0-d7/a0-a6,-(sp)   ;save all
  1602.                move.l  conhandle,d1
  1603.  
  1604.         pch1:
  1605.                lea     outline,a1
  1606.                move.b  d0,(a1)
  1607.                move.l  a1,d2
  1608.                move.l  #1,d3               ;one letter
  1609.                move.l  dosbase,a6
  1610.                jsr     write(a6)
  1611.                movem.l (sp)+,d0-d7/a0-a6   ;restore all
  1612.                rts
  1613.  
  1614.         error:
  1615.                move.l  dosbase,a6
  1616.                jsr     IoErr(a6)
  1617.                move.l  d0,d5
  1618.  
  1619.                move.l  #-1,d7              ;flag
  1620.  
  1621.         qu:
  1622.                move.l  conhandle,d1        ;window close
  1623.                move.l  dosbase,a6
  1624.                jsr     close(a6)
  1625.  
  1626.                move.l  dosbase,a1          ;DOS.Lib close
  1627.                move.l  execbase,a6
  1628.                jsr     closelib(a6)
  1629.  
  1630.                EXIT_AMIGA                  ;AssemPro only
  1631.  
  1632.         openfile:                          ;open file
  1633.                move.l  a1,d1               ;pointer to I/O-definition-
  1634.                                            ;text
  1635.                move.l  d0,d2
  1636.                move.l  dosbase,a6
  1637.                jsr     open(a6)
  1638.                tst.l   d0
  1639.                rts
  1640.  
  1641.         dosname: dc.b 'dos.library',0,0
  1642.                align.w
  1643.  
  1644.         dosbase: dc.l 0
  1645.  
  1646.         consolname: dc.b 'CON:0/100/640/100/ ** CLI-Test **',0
  1647.                align.w
  1648.  
  1649.         conhandle: dc.l 0
  1650.  
  1651.         mytext:
  1652.                dc.b $9b,'4;31;40m'
  1653.                dc.b 'underline'
  1654.                dc.b $9b,'3;33;40m',$9b,'5;20H'
  1655.                dc.b '** Hello World !! **',0
  1656.  
  1657.                align
  1658.  
  1659.         outline: dc.w 0                    ;output buffer for pchar
  1660.  
  1661.                end
  1662.  
  1663.         Now that you've done text and character output,its time to move on
  1664.         to text input.
  1665.  
  1666.       6.4.2.Keyboard Input.
  1667.       ---------------------
  1668.         You can read keyboard input very easily.You just need to open the
  1669.         I/O channel of the CON:window and read from it.You need the read 
  1670.         function from the DOS library to do this.Its offset is -42.
  1671.         The function has three parameters just like the WRITE function.
  1672.  
  1673.         In D1   the handle number that you get from the WRITE function.
  1674.         In D2   the address that the data read in is to start.
  1675.         In D3   the number of bytes to read.
  1676.  
  1677.         Here is a subroutine that reads the number of characters from the
  1678.         keyboard that it finds in D3.It puts them in a buffer.
  1679.  
  1680.         read    = -42                 ; (6.4.2A)
  1681.                ...
  1682.  
  1683.         getchr:                       ;* Get (D3) characters from the
  1684.                                       ;keyboard
  1685.                move.l  #inbuff,d2     ;address of buffer in D2
  1686.                move.l  dosbase,a6     ;DOS base address in A6
  1687.                move.l  conhandle,d1   ;our window handle
  1688.                jsr     read(a6)       ;call read function
  1689.                rts                    ;done!
  1690.  
  1691.         inbuff:        blk.b 80,0     ;buffer for keyboard input
  1692.  
  1693.         This routine returns to the main program when <Return> is entered.
  1694.         If more than D3 characters are entered,"inbuff"only gets the first
  1695.         characters.The routine gets the remaining characters when called a
  1696.         second time.
  1697.         This sort of input is fairly easy.You can backspace,because only
  1698.         the characters that should be there are put in the memory block
  1699.         starting at "inbuff".The number of characters moved into "inbuff"
  1700.         is put in D0.
  1701.          
  1702.         Try the program out as follows:
  1703.  
  1704.         After opening the CON:window,put the following lines in the main
  1705.         program:
  1706.  
  1707.                move   #80,d3          ;read 80 characters (6.4.2B)
  1708.                bsr    readchr         ;get line from keyboard
  1709.                lea    inline,a0       ;address of line in A0
  1710.                clr.b  0(a0,d0)        ;null byte on the end
  1711.                bsr    pmsg            ;output line again
  1712.         
  1713.         bp:
  1714.  
  1715.         After this comes the code segment that closes the window again.
  1716.         After loading the program into the AssemPro debugger,make "bp"a
  1717.         breakpoint and start the program.(SEKA users start the program
  1718.         with "g run"and enter "bp"as the breakpoint).The program quits at
  1719.         the breakpoint and you can take a look at the results on the
  1720.         screen.Then you can continue the program (SEKA with "j bp") and
  1721.         let the window close.
  1722.         After starting the program and opening the window,the cursor
  1723.         appears in the upper left corner of the window.Enter some text and
  1724.         press <Return>.The string that you just entered is output again on
  1725.         the screen.
  1726.         You use the "pmsg"routine from the previous chapter to do this
  1727.         output.This routine needs a null byte at the end of the text to be
  1728.         output.You put a null byte there by putting the address of the
  1729.         input buffer in A0 and then erasing the byte at A0+D0 using the
  1730.         CLR.B command.Since D0 contains the number of characters that were
  1731.         entered,this byte is the first unused byte.
  1732.         Since you're in the debugger you can redisplay the disassembled
  1733.         output when the program ends to see what "getchr"put in "inbuff"
  1734.         (SEKA owners can use "q inbuff"when the program ends to see what
  1735.         "getchr"put there.)You'll find the characters that you typed plus
  1736.         a closing $A.The $A stands for the <Return> key and its counted
  1737.         too,so if you entered a 12 and then hit <Return>,for example,D0
  1738.         will contain a 3.
  1739.         Try this again with a RAW:window.Change the window definition from
  1740.         CON: to RAW:and reassemble the program.You'll notice the diference
  1741.         right away.After you've entered one character,a return is executed
  1742.         D0 always as one bit in it.
  1743.         The advantage of this form of input is that cursor and function
  1744.         keys can be recognized.Using your own routine,you can repeatedly
  1745.         accept input of characters using "getchr"and then work with the
  1746.         special characters.
  1747.         Theres another form of keyboard input:checking for a single key.
  1748.         This is important when a program is about to execute an important
  1749.         function and the user must say he wants it executed by entering
  1750.         "Y"for yes.This can be treated as normal input,but in some cases,
  1751.         there is a better method.
  1752.         There is a function in the DOS library that waits a certain
  1753.         specified length of time for a key to be pressed,and returns a
  1754.         zero (FALSE) if no key was hit in this time period.It returns a -1
  1755.         ($FFFFFFFF = TRUE) if one was.To find out which key it takes
  1756.         another function.The WaitForChar function,is only good for tasks
  1757.         like waiting for the user to let the program know that it can
  1758.         continue scrolling text.
  1759.  
  1760.         The function needs two parameters:
  1761.  
  1762.         In D1    the handle number of the window or file from which the
  1763.                  character should be read.It can also wait for a character
  1764.                  from an interface.
  1765.         In D2    you pass the length of time in microseconds that you
  1766.                  should wait for a key stroke.
  1767.  
  1768.         To wait one second for one key to be hit,you can use the following
  1769.         routine:
  1770.  
  1771.         WaitForCh=-30-174                 ; (6.4.2C)
  1772.                ...
  1773.  
  1774.         scankey:                          ;* Wait for a key stroke
  1775.                move.l  conhandle,d1       ;in our window
  1776.                move.l  #1000000,d2        ;waiting time 1 second
  1777.                move.l  dosbase,a6         ;DOS base address
  1778.                jsr     waitforch(a6)      ;wait...
  1779.                tst.l   d0                 ;test result
  1780.                rts
  1781.  
  1782.         The TST command at the end of the program allows the calling
  1783.         routine to use a BEQ or BNE command to evaluate the results of the
  1784.         routine-BEQ branches if no key was hit.BNE doesn't.
  1785.         Heres an example program in AssemPro format covering what you have
  1786.         learned so far.Opening and closing a window,displaying text in the
  1787.         window and inputting text:
  1788.  
  1789.         ;***** 6.4.2A.ASM S.D *****
  1790.  
  1791.         openlib    =-30-378
  1792.         closelib   =-414
  1793.         ;execbase  =4                      ;defined in AssemPro
  1794.                                            ;Macros
  1795.  
  1796.         * call to Amiga.Dos:
  1797.  
  1798.         open       =-30
  1799.         close      =-30-6
  1800.         read       =-42
  1801.         write      =-48
  1802.         IoErr      =-132
  1803.         mode_old   =1005
  1804.         alloc_abs  =-$cc
  1805.  
  1806.                ILABEL AssemPro:include/Amiga.l  ;AssemPro only
  1807.  
  1808.                INIT_AMIGA                  ;AssemPro only
  1809.  
  1810.         run:
  1811.                bsr     init                ;initialization
  1812.                bsr     test                ;system test
  1813.                nop                         
  1814.                bra     qu                  ;quit and exit
  1815.  
  1816.         test:
  1817.                move.l  #mytext,d0
  1818.                bsr     pmsg
  1819.                bsr     pcrlf
  1820.                bsr     pcrlf
  1821.                move.l  #80,d3              ;80 characters to read in (D3)
  1822.                bsr     getchr              ;get character
  1823.                bsr     pmsg                ;output line
  1824.  
  1825.                rts
  1826.  
  1827.         init:                              ;system initialization and open
  1828.                move.l  execbase,a6         ;number of execute-library
  1829.                lea     dosname(pc),a1
  1830.                moveq   #0,d0
  1831.                jsr     openlib             ;open DOS-Library
  1832.                move.l  d0,dosbase
  1833.                beq     error
  1834.   
  1835.                lea     consolname(pc),a1   ;console definition
  1836.                move.l  #mode_old,d0
  1837.                bsr     openfile            ;console open
  1838.                beq     error
  1839.                move.l  d0,conhandle
  1840.  
  1841.                rts
  1842.  
  1843.         pmsg:                              ;print message (D0)
  1844.                movem.l d0-d7/a0-a6,-(sp)
  1845.                move.l  d0,a0
  1846.                move.l  a0,d2
  1847.                clr.l   d3
  1848.  
  1849.         ploop:
  1850.                tst.b   (a0)+
  1851.                beq     pmsg2
  1852.                addq.l  #1,d3
  1853.                bra     ploop               ;check length
  1854.  
  1855.         pmsg2:
  1856.                move.l  conhandle,d1
  1857.                move.l  dosbase,a6
  1858.                jsr     write(a6)
  1859.                movem.l (sp)+,d0-d7/a0-a6
  1860.                rts
  1861.  
  1862.         pcrlf:
  1863.                move    #10,d0
  1864.                bsr     pchar
  1865.                move    #13,d0
  1866.  
  1867.         pchar:                             ;character in D0 output
  1868.                movem.l d0-d7/a0-a6,-(sp)   ;save all
  1869.                move.l  conhandle,d1
  1870.  
  1871.         pch1:
  1872.                lea     outline,a1
  1873.                move.b  d0,(a1)
  1874.                move.l  a1,d2
  1875.                move.l  #1,d3               ;1 letter
  1876.                move.l  dosbase,a6
  1877.                jsr     write(a6)
  1878.                movem.l (sp)+,d0-d7/a0-a6   ;restore all
  1879.                rts
  1880.  
  1881.         getchr:                            ;get character for keyboard
  1882.                move.l  #1,d3               ;1 character
  1883.                move.l  conhandle,d1
  1884.                lea     inbuff,a1           ;buffer address
  1885.                move.l  a1,d2
  1886.                move.l  dosbase,a6
  1887.                jsr     read(a6)
  1888.                clr.l   d0
  1889.                move.b  inbuff,d0
  1890.                rts
  1891.  
  1892.         error:
  1893.                move.l  dosbase,a6
  1894.                jsr     IoErr(a6)
  1895.                move.l  d0,d5
  1896.  
  1897.                move.l  #-1,d7              ;flag
  1898.  
  1899.         qu:
  1900.                move.l  conhandle,d1        ;window close
  1901.                move.l  dosbase,a6
  1902.                jsr     close(a6)
  1903.  
  1904.                move.l  dosbase,a1          ;DOS.Lib close
  1905.                move.l  execbase,a6 jsr     ;close lib (A6)
  1906.  
  1907.                EXIT_AMIGA                  ;AssemPro only
  1908.  
  1909.  
  1910.         openfile:                          ;open file
  1911.                move.l  a1,d1               ;pointer to I/O-Definition-
  1912.                                            ;Text
  1913.                move.l  d0,d2               
  1914.                move.l  dosbase,a6
  1915.                jsr     open(a6)
  1916.                tst.l   d0
  1917.                rts
  1918.  
  1919.         dosname: dc.b 'dos.library',0,0
  1920.                align.w
  1921.  
  1922.         dosbase: dc.l 0
  1923.  
  1924.         consolname: dc.b 'CON:0/100/640/100/** CLI-TEST **',0
  1925.                align.w
  1926.  
  1927.         conhandle: dc.l 0
  1928.  
  1929.         mytext: dc.b '** Hello World !! **',0
  1930.  
  1931.                align
  1932.  
  1933.         outline: dc.w 0                     ;output buffer for pchar 
  1934.     
  1935.         inbuff: blk.b 8                     ;input buffer
  1936.  
  1937.                end
  1938.  
  1939.  
  1940.       6.4.3.Printer Control.
  1941.       ----------------------
  1942.         Now that you've looked at console I/O,lets look at outputting data
  1943.         from the computor.The first device that we'll discuss is the
  1944.         printer.
  1945.         Its very easy to use the printer.You just need to open another
  1946.         channel.It goes just the way you learned it with CON: and RAW:
  1947.         windows;the only difference is you enter PRT:instead.
  1948.         You open this channel using the same lines that you used above for
  1949.         the window except that the pointer is to the channel name PRT:in
  1950.         D1.You pass the mode "new"(1006) in D2 in the "do_open"routine as
  1951.         well.Save the handle number that comes back at a label called
  1952.         "prthandle".
  1953.         Now you can use the same output routines that you used with the
  1954.         windows to send text to the printer.You need to put "prthandle"
  1955.         instead of "conhandle"in the line with the "move.l conhandle,d1"
  1956.         command.
  1957.         Actually it would be better to eliminate this line from the
  1958.         routine totally.Then you can use the same routine for window and
  1959.         printer output.The calling procedure would then need to put
  1960.         "conhandle"in D1 for window output.It would put "prthandle" in D1
  1961.         for printer output.This is a very flexible output routine that can
  1962.         be used for window and printer output now.You can't accept input
  1963.         from the printer,because the printer doesn't send data.It just
  1964.         accepts it and prints it.
  1965.  
  1966.       6.4.4.Serial I/O.
  1967.       -----------------
  1968.         Its just as easy to use the serial interface as the printer.Just
  1969.         enter SER:as the filename.Now you can use the DOS functions READ
  1970.         and WRITE just as before to do I/O channels you've just opened.
  1971.         You can set the parameters for the interface (like Hand shake and
  1972.         Transfer rate) with the Preferences program. 
  1973.  
  1974.       6.4.5.Speech Output.
  1975.       --------------------
  1976.         The Amiga has a speech synthesizer built in.This isn't quite as
  1977.         easy to program as the I/O devices discussed earlier,however.You
  1978.         use the "narrator.device"to do this.
  1979.         This device requires several program steps to install it and then
  1980.         causes it to speak.You need to open the device,start the I/O,etc..
  1981.         Lets look at how to translate the text into the proper form and
  1982.         then output the text.
  1983.         First we need to do some initialization.Lets define the constants
  1984.         now.Some of them are new.
  1985.  
  1986.         ;***** Narrator Basic Functions 3/87 S.D ***** (6.4.5A)
  1987.  
  1988.         openlib     =-408                   
  1989.         closelib    =-414
  1990.         execbase    = 4
  1991.  
  1992.         open        =-30                    ;open file
  1993.         close       =-36                    ;close file
  1994.         mode_old    = 1005                  ;old mode
  1995.         
  1996.         opendevice  =-444                   ;open device
  1997.         closedev    =-450                   ;close device
  1998.  
  1999.         sendIo      =-462                   ;start I/O
  2000.         abortIO     =-480                   ;abort I/O
  2001.  
  2002.         translate   =-30                    ;translate text
  2003.  
  2004.         ;The initialization routine follows:
  2005.                
  2006.         init:                               ;initialize and open system
  2007.  
  2008.         ;* open DOS library * 
  2009.  
  2010.                move.l  execbase,a6          ;pointer to execbase
  2011.                lea     dosname,a1           ;pointer to DOS name
  2012.                moveq   #0,d0                ;version unimportant
  2013.                jsr     openlib(a6)          ;open DOS library
  2014.                move.l  d0,dosbase           ;save handle
  2015.                beq     error                ;error handle
  2016.  
  2017.         ;* Open translator.library *
  2018.  
  2019.                lea     transname,a1         ;pointer to translator name
  2020.                clr.l   d0 
  2021.                jsr     openlib(a6)          ;open translator
  2022.                move.l  d0,transbase         ;save handle
  2023.                beq     error                ;error handling
  2024.  
  2025.         ;* Set up I/O area for Narrator *
  2026.  
  2027.                lea     talkio,a1            ;pointer to I/O area in A1
  2028.                move.l  #nwrrep,14(a1)       ;enter port address
  2029.                move.l  #amaps,48+8(a1)      ;pointer to audio mask
  2030.                move    #4,48+12(a1)         ;number of the mask
  2031.                move.l  #512,36(a1)          ;length of the output area
  2032.                move    #3,28(a1)            ;command:write
  2033.                move.l  #outtext,40(a1)      ;address of output area
  2034.  
  2035.         ;* Open Narrator device *
  2036.  
  2037.                clr.l   d0                   ;number 0
  2038.                clr.l   d1                   ;no flags
  2039.                lea     nardevice,a0         ;pointer to device name
  2040.                jsr     opendevice(a6)       ;open narrator.device
  2041.                tst.l   d0                   :error?
  2042.                bne     error                ;Yes!
  2043.  
  2044.         ;* Open Window *
  2045.  
  2046.                move.l  #consolname,d1       ;console definition
  2047.                move.l  #mode_old,d2         ;old mode
  2048.                move.l  dosbase,a6           ;DOS base address
  2049.                jsr     open(a6)             ;open window
  2050.                tst.l   d0                   ;error?
  2051.                beq     error                ;Yes!
  2052.                move.l  d0,conhandle         ;else save handle
  2053.  
  2054.         After you've done this initialization,you can have the computor
  2055.         save the text you have prepared for it.To see what the Amiga is
  2056.         saying,use the "pmsg"function to have the text written to the
  2057.         window:
  2058.  
  2059.  
  2060.                move.l  #intext,d2           ;text for the Amiga to say
  2061.                bsr     pmsg                 ;output in window also
  2062.  
  2063.         sayit:                              ;have the text said
  2064.  
  2065.         ;*Translate the text into a form that the computor can use *
  2066.  
  2067.                lea     intext,a0            ;address of the text
  2068.                move.l  #outtext-intext,d0   ;length of the text
  2069.                lea     outtext,a1           ;address of output area
  2070.                move.l  #512,d1              ;length of output area
  2071.                move.l  tranbase,a6          ;translator base address
  2072.                jsr     translate(a6)        ;translate text
  2073.  
  2074.         ;* Speech output *
  2075.  
  2076.                lea     talkio,a1            ;address of I/O structure
  2077.                move.l  #512,36(a1)          ;length of output area
  2078.                move.l  execbase,a6          ;EXEC base address
  2079.                jsr     sendIO(a6)           ;start I/O (speech output)
  2080.  
  2081.  
  2082.         Once the program ends,the I/O stops as well,so you need to put in
  2083.         something that keeps the program going longer.You'll use the
  2084.         "getchr"function that you programmed earlier to take care of this:
  2085.  
  2086.  
  2087.                bsr     getchr               ;wait for keyboard input
  2088.  
  2089.         The computor waits until the <Return> key is pressed.Now you can
  2090.         listen to what the Amiga as to say.Once the <Return> key is
  2091.         pressed,the program stops.
  2092.  
  2093.  
  2094.         qu:                                 ; (6.4.5C)
  2095.                move.l  execbase,a6          ;EXEC base address
  2096.                lea     talkio,a1            ;pointer to I/O area
  2097.                jsr     abortio(a6)          ;stop the I/O
  2098.  
  2099.                move.l  conhandle,d1         
  2100.                move.l  dosbase,a6
  2101.                jsr     close(a6)            ;close window
  2102.                
  2103.                move.l  dosbase,d1
  2104.                move.l  execbase,a6
  2105.                jsr     closelib(a6)         ;close DOS library
  2106.  
  2107.                lea     talkio,a1
  2108.                jsr     closedev(a6)         ;close narrator.device
  2109.  
  2110.                move.l  tranbase,a1              
  2111.                jsr     closelib(a6)         ;close translator library
  2112.  
  2113.                rts                          ;* end of program
  2114.  
  2115.  
  2116.         Now comes the data that you need for the program above:
  2117.  
  2118.  
  2119.         mytext:      dc.b  'This is a test text !',10,13,10,13,0,0
  2120.         dosmame:     dc.b  'dos.library',0,0
  2121.         transname:   dc.b  "translator.library",0
  2122.         consolname:  dc.b  'RAW:0/100/640/100/** Test window',0
  2123.         nardevice    dc.b  'narrator.device',0
  2124.            align
  2125.         dosbase:     dc.l  0
  2126.         tranbase     dc.l  0
  2127.         amaps:       dc.b  3,5,10,12
  2128.            align
  2129.         conhandle:   dc.l  0
  2130.         talkio:      blk.l 20,0
  2131.         nwrrep:      blk.l 8,0
  2132.         intext:      dc.b  'hello,i am the amiga talking to you',0
  2133.            align
  2134.         outtext:     blk.b 512,0
  2135.  
  2136.  
  2137.         This is quite a bit of work,but its worth it because it opens so
  2138.         many possibilities for you.There are a lot of variations possible
  2139.         if you modify parameters.These parameters are entries in the I/O
  2140.         area starting at the "talkio"label.The area is built as follows:
  2141.  
  2142.         Offset        Length       Meaning
  2143.         ----------------------------------------------------------------
  2144.         ** Port Data **
  2145.           0             L          Pointer to next block 
  2146.           4             L          Pointer to last block
  2147.           8             B          I/O type
  2148.           9             B          Priority
  2149.           10            L          Pointer to I/O name
  2150.           14            L          Pointer to port
  2151.           18            W          Length
  2152.         ** I/O Data **
  2153.           20            L          Pointer to device
  2154.           24            L          Pointer to device unit
  2155.           28            W          Command word
  2156.           30            B          I/O flags
  2157.           31            B          I/O status
  2158.           32            L          I/O pointer
  2159.           36            L          I/O length
  2160.           40            L          Pointer to Data
  2161.           44            L          I/O offset
  2162.         ** Narrator data items **
  2163.           48            W          Speech speed
  2164.           50            W          Highness of voice
  2165.           52            W          Speech mode
  2166.           54            W          Sex (male/female voice)
  2167.           56            L          Pointer to audio mask
  2168.           60            W          Number of mask
  2169.           62            W          Volume
  2170.           64            W          Read in rate
  2171.           66            B          Flag for producing graphics (0=off)
  2172.           67            B          Actual mask (internal use)
  2173.           68            B          Channel used (internal use)
  2174.  
  2175.         We would'nt recommend experimenting with the data in the first two
  2176.         blocks.If you do,you can easily cause a system crash.You can use
  2177.         the last entries of the structure to produce some interesting
  2178.         effects though.
  2179.         Heres an overview of the parameters you can use to vary the speech
  2180.         output.The value in parenthesis is the standard value,the value
  2181.         set when narrator.device is opened.
  2182.  
  2183.       Speech speed (150);
  2184.         You can use this to set the speed of speech.The pitch of the voice
  2185.         is not affected by this value.
  2186.  
  2187.       Pitch of voice (110);
  2188.         You can choose a value between 65 and 320 for the pitch (from
  2189.         Goofy to Mickey Mouse).  
  2190.  
  2191.       Speech mode (0);
  2192.         The zero gives half-way naturel speech.A one lets the Amiga speak
  2193.         in monotone like a robot.
  2194.  
  2195.       Sex (0);
  2196.         A zero means masculine and a one means feminine (more or less..)
  2197.  
  2198.       Volume (64);
  2199.         The volume can range from 0 to 64.The standard value is the
  2200.         loudest possible.
  2201.  
  2202.       Read in rate (22200);
  2203.         By lowering this value,the voice is lowered.If you change this
  2204.         very much,you'll get some wierd voices!
  2205.  
  2206.         You can experiment a bit until you find a interesting voice.Have
  2207.         fun! 
  2208.         Here is a complete talking program in AssemPro format:
  2209.  
  2210.         ;***** Speech output S.D. *****
  2211.  
  2212.         openlib      =-30-378
  2213.         closelib     =-414
  2214.         ;execbase    =4                     ;defined by AssemPro
  2215.  
  2216.         * calls to Amiga Dos:         
  2217.  
  2218.         open         =-30
  2219.         close        =-30-6
  2220.         opendevice   =-444
  2221.         closedev     =-450
  2222.         addport      =-354
  2223.         remport      =-360
  2224.         ;DoIo        =-456
  2225.         sendIo       =-462
  2226.         abortIo      =-480
  2227.         read         =-30-12
  2228.         write        =-30-18
  2229.         ;myinput     =-30-24
  2230.         ;output      =-30-30
  2231.         ;currdir     =-30-96
  2232.         ;exit        =-30-114
  2233.         waitforch    =-30-174
  2234.         findtask     =-294
  2235.         translate    =-30
  2236.         mode_old     = 1005
  2237.         ;mode_new    = 1006
  2238.         ;alloc_abs   =-$cc
  2239.         ;free_mem    =-$d2
  2240.  
  2241.         ;!!!when>500KB !!! or place in chip memory
  2242.         ;org $40000
  2243.         ;load $40000
  2244.         ;!!!!!!!!!!!!!!!!!!!!!!!
  2245.  
  2246.                
  2247.                ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
  2248.  
  2249.                INIT_AMIGA                   ;AssemPro only
  2250.  
  2251.         run:
  2252.                bsr     init                 ;initialization
  2253.                bra     test                 ;system-test
  2254.  
  2255.         init:                               ;system initialization and
  2256.                                             ;open
  2257.                move.l  execbase,a6          ;pointer to exec library
  2258.                lea     dosname(pc),a1       ;pointer to dos name
  2259.                moveq   #0,d0                ;version:not important
  2260.                jsr     openlib(a6)          ;open DOS-Library
  2261.                move.l  d0,dosbase           ;save handle
  2262.                beq     error                ;error routine
  2263.  
  2264.         ;*                                  ;open translator library
  2265.                move.l  execbase,a6          ;pointer to exec library
  2266.                lea     transname,a1         ;pointer to translator library
  2267.                clr.l   d0
  2268.                jsr     openlib(a6)          ;open translator
  2269.                move.l  d0,tranbase          ;save handle
  2270.                beq     error                ;error routine
  2271.  
  2272.         ;*                                  ;set up
  2273.                sub.l   a1,a1
  2274.                move.l  execbase,a6
  2275.                jsr     findtask(a6)         ;find task
  2276.                move.l  d0,nwrrep+2
  2277.  
  2278.                lea     nwrrep,a1
  2279.                jsr     addport(a6)          ;add port
  2280.  
  2281.         ;*                                  ;open narrator device
  2282.                lea     talkio,a1            ;pointer to I/O area in A1
  2283.                move.l  #nwrrep,14(a1)       ;enter port address
  2284.                clr.l   d0                   ;number 0
  2285.                clr.l   d1                   ;no flags
  2286.                lea     nardevice,a0         ;pointer to device name
  2287.                jsr     opendevice(a6)       ;open narrator.device
  2288.                tst.l   d0                   ;error?
  2289.                bne     error                ;Yes!
  2290.  
  2291.         ;*                                  ;set up I/O for narrator
  2292.                                             ;device
  2293.  
  2294.         bp:
  2295.                lea     talkio,a1            ;pointer to I/O in A1
  2296.                move.l  #nwrrep,14(a1)       ;enter port address
  2297.                move.l  #amaps,48+8(a1)      ;pointer to audio mask
  2298.                move    #4,48+12(a1)         ;size of mask
  2299.  
  2300.                lea     consolname(pc),a1    ;console-definition
  2301.                move.l  #mode_old,d0
  2302.                bsr     openfile             ;console open
  2303.                beq     error        
  2304.                move.l  d0,conhandle
  2305.  
  2306.                rts
  2307.  
  2308.         test:
  2309.                move.l  #mytext,d0           
  2310.                bsr     pmsg                 ;test-text output 
  2311.  
  2312.                bsr     sayit                ;say text
  2313.  
  2314.                bsr     readin               ;input
  2315.                move    #10,d0
  2316.                bsr     pchar                ;LF output
  2317.                move.l  #inline+2,d0
  2318.                bsr     pmsg                 ;and again
  2319.                bsr     pcrlf
  2320.                bra     qu
  2321.  
  2322.         error:
  2323.                move.l  #-1,d7               ;flag
  2324.  
  2325.         qu:
  2326.                move.l  execbase,a6 
  2327.                lea     talkio,a1
  2328.                jsr     abortio(a6)
  2329.         
  2330.                move.l  conhandle,d1         ;window close
  2331.                move.l  dosbase,a6
  2332.                jsr     close(a6)
  2333.  
  2334.                move.l  dosbase,a1           ;DOS.Lib close
  2335.                move.l  execbase,a6
  2336.                jsr     closelib(a6)
  2337.  
  2338.                lea     nwrrep,a1
  2339.                jsr     remport(a6)          ;remove port
  2340.                lea     talkio,a1
  2341.                jsr     closedev(a6)         ;close narrator device
  2342.                move.l  tranbase,a1
  2343.                jsr     closelib(a6)         ;close translator library
  2344.  
  2345.                EXIT_AMIGA                   ;AssemPro only
  2346.  
  2347.         openfile:                           ;open file
  2348.                move.l  a1,d1                ;pointer to I/O definition-
  2349.                                             ;text
  2350.                move.l  d0,d2
  2351.                move.l  dosbase,a6
  2352.                jsr     open(a6)
  2353.                tst.l   d0
  2354.                rts
  2355.  
  2356.         pmsg:                               ;print message (D0)
  2357.                movem.l d0-d7/a0-a6,-(sp)    
  2358.                move.l  d0,a0
  2359.                move.l  a0,d2
  2360.                clr.l   d3
  2361.  
  2362.         mess1:
  2363.                tst.b   (a0)+
  2364.                beq     mess2
  2365.                addq.l  #1,d3
  2366.                bra     mess1                ;length calculate
  2367.  
  2368.         mess2:
  2369.                move.l  conhandle,d1
  2370.                move.l  dosbase,a6
  2371.                jsr     write(a6)
  2372.                movem.l (sp)+,d0-d7/a0-a6
  2373.                rts
  2374.  
  2375.         pcrlf:
  2376.                move    #10,d0
  2377.                bsr     pchar
  2378.                move    #13,d0
  2379.  
  2380.         pchar:                              ;output characters in D0
  2381.                movem.l d0-d7/a0-a6,-(sp)    ;save all
  2382.                move.l  conhandle,d1
  2383.  
  2384.         pch1:
  2385.                lea     chbuff,a1
  2386.                move.b  d0,(a1)
  2387.                move.l  a1,d2
  2388.                move.l  #1,d3                ;1 letter
  2389.                move.l  dosbase,a6
  2390.                jsr     write(a6)
  2391.                movem.l (sp)+,d0-d7/a0-a6    ;restore all
  2392.                rts
  2393.  
  2394.         scankey:                            ;test key
  2395.                move.l  conhandle,d1
  2396.                move.l  #500,d2              ;wait value
  2397.                move.l  dosbase,a6
  2398.                jsr     waitforch(a6)
  2399.                tst.l   d0
  2400.                rts
  2401.  
  2402.         readin:                             ;input from keyboard
  2403.                movem.l d0-d7/a0-a6,-(sp)    ;save registers
  2404.                lea     inline+2,a2          ;pointer to input buffer
  2405.                clr.l   (a2)
  2406.  
  2407.         inplop:
  2408.                bsr     getchr
  2409.                cmp.b   #8,d0
  2410.                beq     backspace
  2411.                cmp.b   #127,d0              ;delete?
  2412.                beq     backspace
  2413.                bsr     pchar                ;character output
  2414.                cmp.b   #13,d0
  2415.                beq     inputx
  2416.                move.b  d0,(a2)+
  2417.                bra     inplop
  2418.  
  2419.         inputx:
  2420.                clr.b   (a2)+
  2421.                sub.l   #inline,a2
  2422.                move    a2,inline            ;length in lines+1
  2423.                movem.l (sp)+,d0-d7/a0-a6    ;registers
  2424.                rts
  2425.  
  2426.         backspace:
  2427.                cmp.l   #inline,a2           ;at the beginning?
  2428.                beq     inplop               ;yes
  2429.                move.b  #8,d0
  2430.                bsr     pchar                ;backspace
  2431.                move    #32,d0
  2432.                bsr     pchar                ;blank
  2433.                move    #8,d0
  2434.                bsr     pchar                ;backspace
  2435.                clr.b   (a2)
  2436.                subq.l  #1,a2
  2437.                bra     inplop
  2438.  
  2439.         getchr:                             ;get one character from
  2440.                                             ;keyboard
  2441.                move.l  #1,d3                ;one character
  2442.                move.l  conhandle,d1      
  2443.                lea     inbuff,a1            ;buffer address
  2444.                move.l  a1,d2
  2445.                move.l  dosbase,a6
  2446.                jsr     read(a6)
  2447.                clr.l   d0
  2448.                move.b  inbuff,d0
  2449.                rts
  2450.  
  2451.         sayit:
  2452.                lea     intext,a0
  2453.                move.l  #outtext-intext,d0
  2454.                lea     outtext,a1
  2455.                move.l  #512,d1
  2456.                move.l  tranbase,a6
  2457.                jsr     translate(a6)
  2458.  
  2459.         p:
  2460.                lea     talkio,a1
  2461.                move    #3,28(a1)            ;??
  2462.                move.l  #512,36(a1)
  2463.                move.l  #outtext,40(a1)
  2464.                move.l  execbase,a6
  2465.                jsr     sendio(a6)
  2466.                
  2467.                rts
  2468.  
  2469.         mytext:        dc.b 'This is our Test-Text !',10,13,10,13,0,0
  2470.  
  2471.         dosname:       dc.b 'dos.library',0,0
  2472.  
  2473.         transname:     dc.b "translator.library",0
  2474.                align.w
  2475.  
  2476.         dosbase:       dc.l 0
  2477.   
  2478.         tranbase:      dc.l 0
  2479.  
  2480.         consolname:    dc.b 'CON:0/100/640/100/* Speech-Test S.D.* ',0
  2481.  
  2482.         nardevice:     dc.b 'narrator.device',0
  2483.  
  2484.         amaps:         dc.b 3,5,10,12,0,0
  2485.                align.w
  2486.  
  2487.         conhandle:     dc.l 0
  2488.  
  2489.         inbuff:        blk.b 8
  2490.  
  2491.         inline:        blk.b 180,0
  2492.      
  2493.         chbuff:        blk.b 82,0
  2494.  
  2495.         narread:       blk.l 20,0
  2496.    
  2497.         talkio:        blk.l 20,0
  2498.  
  2499.         nwrrep:        blk.l 8,0
  2500.  
  2501.         intext:        dc.b 'hello,i am the amiga computor',0
  2502.                align.w
  2503.  
  2504.         outtext:       blk.l 128,0
  2505.  
  2506.         
  2507.         end
  2508.  
  2509.       6.5.Disk Operations.
  2510.       --------------------
  2511.         The most important peripheral device for a computor like the Amiga
  2512.         is the disk drive.You use it to save data,so that you don't lose
  2513.         it when you turn off the computor.We'll look at saving and
  2514.         retrieving data in this chapter.                                  
  2515.         Lets first look at the simple disk operations that are used for
  2516.         data management.To gain access to a file,you must open it first.  
  2517.         This is done using the OPEN function from the DOS library,a
  2518.         function that you're already familiar with.I'll assume in the
  2519.         following examples,that you've already opened the DOS library.
  2520.  
  2521.       6.5.1.Open Files.
  2522.       -----------------
  2523.         The open function needs a parameter for the mode.The mode has a
  2524.         particular meaning.If the file is opened for reading,it must
  2525.         already exist.The mode for the OPEN function must be "old"(1005)
  2526.         in this case.
  2527.         If you want to produce a file,you must open it first.Since it does
  2528.         not exist,you use the "new"(1006) mode.If a file is opened for
  2529.         writing using this mode even though a file with this name already
  2530.         exists,the old file with this name is erased and replaced.To avoid
  2531.         loss of data,you should check if a file by that name already
  2532.         exists and then output an error message if it does.
  2533.         You're going to start with a subroutine that opens a file.Lets
  2534.         assume that the filename starts at the label "filename",and that
  2535.         it is closed with a null byte.You just need to pass the mode in
  2536.         register D2.
  2537.         The routine puts the file handle number in "filehd"and returns to
  2538.         the main program.Since the operation with the handle is the last
  2539.         one performed by the subroutine,the status of the operation can be
  2540.         evaluated once the return has been executed.If the operation went
  2541.         smoothly and the file is opened,the handle number has a non-zero
  2542.         value.If it is zero and "bsr openfile"is followed by "beq error", 
  2543.         you can branch to an error handling routine when problems occur.
  2544.  
  2545.         Here is a subroutine for opening and closing a file:
  2546.  
  2547.         open       =-30                   ; (6.5.1A)                    
  2548.         close      =-36
  2549.         mode_old   = 1005
  2550.         mode_new   = 1006
  2551.              ...
  2552.         openfile:                       ;*open file,mode in D0
  2553.                move.l  dosbase,a6       ;DOS base address in A6
  2554.                move.l  #filename,d1     ;pointer to filename
  2555.                jsr     open(a6)         ;open file
  2556.                move.l  d0,filehd        ;save handle
  2557.                rts
  2558.  
  2559.         closefile:                      ;*close file
  2560.                move.l  dosbase,a6       ;DOS base address in A6
  2561.                move.l  filehd,d1        ;file handle in D1
  2562.                jsr     close(a6)        ;close file
  2563.                rts
  2564.  
  2565.         filehd:     dc.l   0            ;storage for file handle
  2566.         filename:   dc.b  "filename",0  ;file to be opened
  2567.                align                    ;even
  2568.  
  2569.         To use these subroutines,you must look at how you can load and
  2570.         save data.                                                        
  2571.                                                                           
  2572.       6.5.2.Reading and Writing Data.                                     
  2573.       -------------------------------                                     
  2574.         Lets write a new file.To start,write the following lines:      
  2575.  
  2576.                 move.l  #mode_new,d2    ;open new file (6.5.2A)
  2577.                 bsr     openfile        ;open file
  2578.                 beq     error           ;did'nt work!
  2579.  
  2580.         For the filename,write a name like "Testfile"in the line labelled 
  2581.         "filename".After calling the "openfile"routine,a file with this
  2582.         name is created on the disk.If one existed already,it is erased.
  2583.  
  2584.         Lets assume you want to write a short text file.For the example
  2585.         lets use:
  2586.  
  2587.         text:  dc.b   "This is a test text for the Testfile",0
  2588.         textend:
  2589.  
  2590.         The "textend"label is used so that you can calculate the number of
  2591.         data bytes by subtracting "text".
  2592.         You want to write this text in the file.Use the WRITE function
  2593.         which needs three parameters:
  2594.  
  2595.         In D1   the file handle that you got back from the OPEN function.
  2596.         In D2   a pointer to the data that should be written.
  2597.         In D3   the number of bytes to be written.
  2598.  
  2599.         For the example,you'll need another segment of code to put the
  2600.         pointer to the data in D2 and the number of bytes in D3:
  2601.  
  2602.         write  =-48                      ; (6.5.2B)
  2603.               ...
  2604.         writedata:                       ;*write data in the file
  2605.               move.l  dosbase,a6         ;DOS base address
  2606.               move.l  filehd,d1          ;file handle in D1
  2607.               jsr     write(a6)          ;write data
  2608.               rts
  2609.  
  2610.         After opening the file,you can call the subroutine from the main
  2611.         program with the following lines: 
  2612.  
  2613.               move.l  #text,d2           ;pointer to data
  2614.               move.l  #textend-text,d3   ;number of bytes
  2615.               bsr     writedata          ;write data in the file
  2616.  
  2617.         Then close the file with:
  2618.  
  2619.               bsr     closefile          ;close file
  2620.               bra     end                ;end program
  2621.  
  2622.         After running the program,look at the directory of the diskette,  
  2623.         you should find the file "testfile".It is just as long as your
  2624.         text.You want to read this file in,to make sure it contains the
  2625.         right data.
  2626.         You need the DOS function READ,which needs the same parameters as
  2627.         the WRITE function.You can use parameters for the number of bytes
  2628.         to read just part of the file.If you give a larger number than the
  2629.         file contains,the whole file is loaded.You'll find the number of
  2630.         bytes read in D0.
  2631.         Lets set up a field that as enough space for the data you want to
  2632.         read.You can do this with the following line:
  2633.  
  2634.         field: blk.b  100     ;reserve 100 bytes
  2635.  
  2636.         For the example data,this is plenty.If you want to load another
  2637.         file,you may need to reserve more space.
  2638.         Now lets write a subroutine to read the data.You always want to
  2639.         load whole files.You just need to pass the address of the buffer
  2640.         so the data is loaded into the subroutine.In the example,its the
  2641.         address "field".
  2642.         Heres the subroutine that reads the entire opened file into the
  2643.         memory area pointed to by D2:
  2644.  
  2645.         read   = -42                  ; (6.5.2C)
  2646.                ...
  2647.         readdata:                     ;*read file
  2648.                move.l  dosbase,a6     ;DOS base address in A6
  2649.                move.l  filehd,d1      ;file handle in D1
  2650.                move.l  #$ffffff,d3    ;read an arbitrary number of bytes
  2651.                jsr     read(a6)       ;read data
  2652.                rts
  2653.  
  2654.         To use this routine to load the file into the buffer "field",use
  2655.         the following main program:
  2656.  
  2657.                move,l  #mode_old,d2   ;old file
  2658.                bsr     openfile       ;open file
  2659.                beq     error          ;did'nt work!
  2660.                move.l  #field,d2      ;pointer to data buffer
  2661.                bsr     readdata       ;read file
  2662.                move.l  d0,d6          ;save number of bytes in D6
  2663.                bsr     closefile      ;close file
  2664.                bra     end            ;program end
  2665.  
  2666.         After assembling and starting this program,you can use the
  2667.         debugger to look at the data buffer that you filled with data from
  2668.         the file.In D6,you'll find the number of bytes that were read from
  2669.         the file. 
  2670.  
  2671.       6.5.3.Erase Files.
  2672.       ------------------
  2673.         Once you've experimented enough with the program above,you'll
  2674.         certainly want to erase the "Testfile"file.The DELETEFILE function
  2675.         in the DOS library has an offset of -72.It only needs 1 parameter.
  2676.         The parameter is passed in D1.The parameter is a pointer to the
  2677.         filename.The name must be closed with a null byte.
  2678.  
  2679.         To erase "Testfile",use the following lines:
  2680.  
  2681.         deletefile  =-72                ; (6.5.3)
  2682.                ...
  2683.                move.l  dosbase,a6       ;DOS base address in A6
  2684.                move.l  #filename,d1     ;pointer to filename in D1
  2685.                jsr     deletefile(a6)   ;erase file
  2686.  
  2687.         The file is deleted.You can't save the file with normal methods if
  2688.         you accidently erase it!You can use a trick that saves the data.  
  2689.         We'll take a look at this trick later.Its used in lots of programs
  2690.  
  2691.       6.5.4.Rename Files.
  2692.       -------------------
  2693.         When a text editing program writes a text that as be altered back
  2694.         to the disk,the old file usually isn't erased.Often the old file
  2695.         is renamed.For example,it might get the name "Backup".The new file
  2696.         is written to disk with the old name.
  2697.         The function in the DOS library that allows you to change the
  2698.         names of programs is called RENAME and has -78 as an offset.You
  2699.         need to pass two parameters-D1 as a pointer to the old name and D2
  2700.         as a pointer to the new name of the file.
  2701.  
  2702.         To rename "Testfile"as "Backup"(before you erase it),use the
  2703.         following lines: 
  2704.  
  2705.         rename  =-78
  2706.                ...
  2707.                move.l  dosbase,a6    ;DOS base address in A6
  2708.                move.l  #oldname,d1   ;pointer to old name in D1
  2709.                move.l  #newname,d2   ;pointer to new name in D2
  2710.                jsr     rename(a6)    ;rename file
  2711.                ...
  2712.         oldname: dc.b "testfile",0
  2713.         newname: dc.b "backup",0
  2714.  
  2715.       6.5.5.CLI Directory.
  2716.       --------------------
  2717.         Lets pretend you've programmed a text editor and started it.Now
  2718.         you want to load a text from disk and edit it-but whats the name
  2719.         of that file?
  2720.         You need a function to read and display the directory of the disk.
  2721.         There are several ways to do this.First lets use the easiest
  2722.         method.It doesn't require much programming and can be quite
  2723.         useful.
  2724.         The trick is to call the Dir or List programs that are in the C   
  2725.         directory.You'll use the CLI commands.The DOS library contains a
  2726.         command called "Execute"with offset -222 that allows you to
  2727.         execute CLI commands. 
  2728.         The function needs three parameters:
  2729.  
  2730.         In D1   a pointer to a string closed with a zero that contains the
  2731.                 name of the command to be executed.This string must
  2732.                 contain the same command that you would give in the CLI.It
  2733.                 can be a null pointer as well.
  2734.         In D2   the input file is determined.Normally theres a zero here. 
  2735.                 If however,you give the file handle of a text file,though,
  2736.                 this file is read and interpreted as a command sequence.If
  2737.                 you define a window as the input medium,you've programmed
  2738.                 a new CLI window!
  2739.         In D3   the output file is determined.If there a zero here,the
  2740.                 output of the commands (for example,DIR output) is sent to
  2741.                 the standard CLI window.
  2742.  
  2743.         To try this out,insert this subroutine in a program that has
  2744.         already opened the DOS library and a window.
  2745.  
  2746.         execute  = -222              ; (6.5.5)
  2747.               ...
  2748.         dir: 
  2749.               move.l  dosbase,a6     ;DOS base address in A6
  2750.               move.l  #command,d1    ;pointer to command line
  2751.               clr.l   d2             ;no input (CLI window)
  2752.               move.l  conhandle,d3   ;output in our window
  2753.               jsr     execute(a6)    ;execute command
  2754.               rts
  2755.  
  2756.         command:
  2757.               dc.b    "dir",0
  2758.  
  2759.         This program works with the List command as well.The disadvantage 
  2760.         of this method is that the disk that the Workbench is loaded from 
  2761.         must be in the drive or the system requests you to put it in.The  
  2762.         Dir command is just a program,and the Amiga must load it before it
  2763.         can run.
  2764.         The disadvantage isn't too great.The program is short,and it
  2765.         allows you to use any CLI command in a program.
  2766.         Here is the complete program in AssemPro format that calls the dir
  2767.         program:
  2768.  
  2769.         ;***** 6.5.5A DIR.ASM S.D.*****   
  2770.         
  2771.         openlib      =-408
  2772.         closelib     =-414
  2773.         ;execbase    = 4                    ;defined in AssemPro
  2774.                                             ;macros
  2775.                        
  2776.                                        
  2777.         *calls to Amiga Dos:
  2778.  
  2779.         open         =-30
  2780.         close        =-36
  2781.         execute      =-222
  2782.         IoErr        =-132
  2783.         mode_old     = 1005
  2784.         alloc_abs    =-$cc
  2785.  
  2786.                ILABEL AssemPro:includes/Amiga.l   ;AssemPro only
  2787.  
  2788.                INIT_AMIGA                   ;AssemPro only                
  2789.                                                                           
  2790.         run:
  2791.                bsr     init                 ;initialization
  2792.                bra     test                 ;system test
  2793.  
  2794.         init:                               ;system initialization and
  2795.                                             ;open
  2796.                move.l  execbase,a6          ;number of execute-library
  2797.                lea     dosname(pc),a1
  2798.                moveq   #0,d0
  2799.                jsr     openlib(a6)          ;open DOS-library
  2800.                move.l  d0,dosbase
  2801.                beq     error
  2802.  
  2803.                lea     consolname(pc),a1    ;console definition
  2804.                move.l  #mode_old,d0
  2805.                bsr     openfile             ;console open
  2806.                beq     error
  2807.                move.l  d0,conhandle
  2808.  
  2809.                rts
  2810.  
  2811.         test:
  2812.                bsr     dir                  ;do directory
  2813.                bra     qu                   ;quit and exit
  2814.  
  2815.         dir:
  2816.                move.l  dosbase,a6           ;DOS base address in A6
  2817.                move.l  #command,d1          ;pointer to command line
  2818.                clr.l   d2                   ;no input (CLI window)
  2819.                move.l  conhandle,d3         ;output in our window
  2820.                jsr     execute(a6)          ;execute command
  2821.                rts
  2822.  
  2823.         error:
  2824.                move.l  dosbase,a6
  2825.                jsr     IoErr(a6)
  2826.                move.l  d0,d5
  2827.  
  2828.                move.l  #-1,d7               ;flag
  2829.  
  2830.         qu:
  2831.                move.l  conhandle,d1         ;window close
  2832.                move.l  dosbase,a6
  2833.                jsr     close(a6)
  2834.  
  2835.                move.l  dosbase,a1           ;DOS.Lib close
  2836.                move.l  execbase,a6
  2837.                jsr     closelib(a6)
  2838.  
  2839.                EXIT_AMIGA                   ;AssemPro only
  2840.  
  2841.         openfile:                           ;open file
  2842.                move.l  a1,d1                ;pointer to I/O-Definition-
  2843.                                             ;text
  2844.                move.l  d0,d2
  2845.                move.l  dosbase,a6
  2846.                jsr     open(a6)
  2847.                tst.l   d0
  2848.                rts
  2849.  
  2850.         dosname: dc.b 'dos.library',0,0
  2851.                align.w
  2852.         dosbase: dc.l 0
  2853.         consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0
  2854.                align.w
  2855.         conhandle: dc.l 0
  2856.         command:
  2857.                dc.b    "dir",0
  2858.  
  2859.                end
  2860.  
  2861.       6.5.6.Read Directory.
  2862.       ---------------------
  2863.         Now,lets look at another method that doesn't need the CLI.In this
  2864.         way,you can read the directory of any disk without having to play
  2865.         Disk Jockey.                                                      
  2866.         You need to writ a program that does what CLI's Dir program does. 
  2867.         There are several steps.
  2868.         First you must give the system a key to the desired directory.That
  2869.         means you must call DOS'Lock function.It needs two parameters:
  2870.  
  2871.         In D1    pass a pointer to a text that contains the name of the
  2872.                  directory you wish to read.If,for example,you want to
  2873.                  read the contents of the RAM disk,the text would be 
  2874.                  'RAM:',0.
  2875.         In D2    put the mode that determines whether to read or write.Let
  2876.                  us use the "Read"(-2) mode.
  2877.  
  2878.         You call the Lock function (offset -84) and get either a point to
  2879.         the key or a zero returned to you in the D0 register.If you get a
  2880.         zero,the call did'nt work,the file was'nt found.This function can
  2881.         be used to find if a file is on the disk.You use this function
  2882.         with the name and see if D0 comes back zero.If not,the file
  2883.         exists.
  2884.         Lets assume the file or path exists.You need to save the value
  2885.         that came back in D0.You'll need it for both functions that you'll
  2886.         call.
  2887.         The next function you need is called Examine.You use it to search 
  2888.         the disk for an acceptable entry.It returns parameters like name, 
  2889.         length and date that correspond to the entry.You need to reserve a
  2890.         memory block for this information and put the beginning of the
  2891.         block in D2 before calling the Examine function.Put the key you
  2892.         got from the Lock function in the D1 register.
  2893.         The memory area that is filled with information is called a
  2894.         FileInfoBlock.Its 260 bytes long and contains information about
  2895.         the file.The name starts in the 9th byte and ends with a null byte
  2896.         so you can easily print it with our "pmsg"routine.The information
  2897.         that Examine gives isn't about a particular file,but about the
  2898.         disk.The name in FileInfoBlock is the disk name.
  2899.         The Examine function sends the status back in the D0 register.
  2900.         Since the Lock function already tested if the file existed,evalua-
  2901.         ting the status really isn't necessary.
  2902.         Now to the function that you can use to read individual files from
  2903.         the directory.The function is called ExNext (Examine Next).This   
  2904.         function searches for the next entry that fits the key every time
  2905.         it is called.ExNext gets the same parameters as Examine gets.     
  2906.         However,the return parameter in D0 is more important here.
  2907.         The ExNext function is always called in the same way.It always
  2908.         gets the next entry of the directory.If no more entries exist in
  2909.         the directory,ExNext puts a zero in the D0 register.
  2910.         You need to continue performing this operation until there aren't 
  2911.         any more entries.You can find this using the IoErr function from
  2912.         the DOS library.
  2913.         This function doesn't need any parameters.It returns the status of
  2914.         the last I/O operation that was performed in the D0 register.After
  2915.         the last ExNext,this value is 232,which means no_more_Entries.
  2916.  
  2917.         Heres a complete routine for reading the directory of the disk in 
  2918.         DFO:and displaying the contents in the window.
  2919.  
  2920.         ; 6.5.5B.ASM
  2921.         ;***** DOS-Sample function  3/87 S.D. *****
  2922.  
  2923.         openlib      =-30-378
  2924.         closelib     =-414
  2925.         exbase       =4
  2926.  
  2927.         * calls to amiga dos:
  2928.  
  2929.         open         =-30
  2930.         close        =-30-6
  2931.         read         =-30-12
  2932.         write        =-30-18
  2933.         myinput      =-30-24
  2934.         output       =-30-30
  2935.         currdir      =-30-96
  2936.         lock         =-30-54
  2937.         examine      =-30-72
  2938.         exnext       =-30-78
  2939.         exit         =-30-114
  2940.         IoErr        =-30-102
  2941.         waitforch    =-30-174
  2942.         mode         = 0
  2943.         mode_old     = 1005
  2944.         mode_new     = 1006
  2945.         alloc_abs    =-$cc
  2946.         free_mem     =-$d2
  2947.  
  2948.                ILABEL AssemPro:includes/Amiga.l   ;AssemPro only
  2949.  
  2950.                INIT_AMIGA                   ;AssemPro only
  2951.  
  2952.         run:                                                              
  2953.                bsr     init                 ;initialization
  2954.                bra     test                 ;system-test
  2955.  
  2956.         init:                               ;system initialization and
  2957.                                             ;open
  2958.                move.l  exbase,a6            ;pointer to exec.library
  2959.                lea     dosname(pc),a1
  2960.                moveq   #0,d0
  2961.                jsr     openlib(a6)          ;open dos-library
  2962.                move.l  do,dosbase
  2963.                beq     error
  2964.  
  2965.                lea     consolname(pc),a1    ;console definition
  2966.                move.l  #mode_old,d0
  2967.                bsr     openfile             ;console open
  2968.                beq     error
  2969.                moveq   d0,conhandle
  2970.  
  2971.                rts
  2972.  
  2973.         test:
  2974.                move.l  #mytext,d0
  2975.                bsr     pmsg                 ;test-text output
  2976.  
  2977.                move.l  dosbase,a6
  2978.                move.l  #name,d1
  2979.                move.l  #-2,d2
  2980.                jsr     lock(a6)
  2981.                move.l  d0,d5
  2982.                tst.l   d0
  2983.                beq     error
  2984.                move.l  d0,locksav
  2985.  
  2986.                move.l  dosbase,a6
  2987.                move.l  locksav,d1
  2988.                move.l  #fileinfo,d2
  2989.                jsr     examine(a6)
  2990.                move.l  d0,d6
  2991.                tst.l   d0
  2992.                beq     error
  2993.  
  2994.         loop:
  2995.                move.l  dosbase,a6
  2996.                move.l  locksav,d1
  2997.                move.l  #fileinfo,d2
  2998.                jsr     exnext(a6)
  2999.                tst.l   d0
  3000.                beq     error
  3001.  
  3002.                move.l  #fileinfo+8,d0
  3003.                bsr     pmsg
  3004.                bsr     pcrlf
  3005.                bra     loop
  3006.  
  3007.         error:
  3008.                move.l  dosbase,a6
  3009.                jsr     ioerr(a6)
  3010.                move.l  d0,d6
  3011.  
  3012.                move.l  #presskey,d0
  3013.                bsr     pmsg
  3014.                bsr     getch
  3015.                move.l  #-1,d7               ;flag
  3016.  
  3017.         qu:
  3018.                move.l  conhandle,d1         ;window close
  3019.                move.l  dosbase,a6
  3020.                jsr     close(a6)
  3021.  
  3022.                move.l  dosbase,a1           ;dos.lib close
  3023.                move.l  exbase,a6
  3024.                jsr     closelib(a6)
  3025.               
  3026.                EXIT_AMIGA                   ;AssemPro only
  3027.  
  3028.         openfile:                           ;open file
  3029.                move.l  a1,d1                ;pointer to I/O-Definition-
  3030.                                             ;Text
  3031.                move.l  d0,d2
  3032.                move.l  dosbase,a6
  3033.                jsr     open(a6)
  3034.                tst.l   d0
  3035.                rts
  3036.  
  3037.         pmsg:                               ;print message (D0)
  3038.                movem.l d0-d7/a0-a6,-(sp)
  3039.                move.l  d0,a0
  3040.                move.l  a0,d2
  3041.                clr.l   d3
  3042.  
  3043.         mess1:
  3044.                tst.b   (a0)+
  3045.                beq     mess2
  3046.                addq.l  #1,d3
  3047.                bra     mess1
  3048.  
  3049.         mess2:
  3050.                move.l  conhandle,d1
  3051.                move.l  dosbase,a6
  3052.                jsr     write(a6)
  3053.                movem.l (sp)+,d0-d7/a0-a6
  3054.                rts
  3055.  
  3056.         pcrlf:
  3057.                move    #10,d0
  3058.                bsr     pchar
  3059.                move    #13,d0
  3060.  
  3061.         pchar:                              ;character in D0 output
  3062.                movem.l d0-d7/a0-a6,-(sp)    ;save all
  3063.                move.l  conhandle,d1
  3064.  
  3065.         pch1:
  3066.                lea     chbuff,a1
  3067.                move.b  d0,(a1)
  3068.                move.l  a1,d2
  3069.                move.l  #1,d3
  3070.                move.l  dosbase,a6
  3071.                jsr     write(a6)
  3072.                movem.l (sp)+,d0-d7/a0-a6    ;restore all
  3073.                rts
  3074.        
  3075.         scankey:                            ;test key
  3076.                move.l  conhandle,d1
  3077.                move.l  #500,d2              ;wait value
  3078.                move.l  dosbase,a6
  3079.                jsr     waitforch(a6)
  3080.                tst.l   d0
  3081.                rts
  3082.  
  3083.         readin:                             ;input from keyboard
  3084.                movem.l d0-d7/a0-a6,-(sp)    ;registers
  3085.                lea     inline+2,a2          ;pointer to input buffer
  3086.                clr.l   (a2)
  3087.  
  3088.         inplop:
  3089.                bsr     getchr
  3090.                cmp.b   #8,d0
  3091.                beq     backspace
  3092.                cmp.b   #127,d0              ;delete?
  3093.                beq     backspace
  3094.                bsr     pchar                ;character output
  3095.                cmp.b   #13,d0
  3096.                beq     inputx
  3097.                move.b  d0,(a2)+
  3098.                bra     inplop
  3099.  
  3100.         input:
  3101.                clr.b   (a2)+
  3102.                sub.l   #inline,a2
  3103.                move    a2,inline            ;length in inline+1
  3104.                movem.l (sp)+,d0-d7/a0-a6    ;registers
  3105.                rts
  3106.  
  3107.         backspace:
  3108.                cmp.l   #inline,a2           ;at beginning?
  3109.                beq     inplop               ;yes
  3110.                move.b  #8,d0
  3111.                bsr     pchar                ;backspace
  3112.                move    #32,d0
  3113.                bsr     pchar                ;blank
  3114.                move    #8,d0
  3115.                bsr     pchar                ;backspace
  3116.                clr.b   (a2)
  3117.                subq.l  #1,a2
  3118.                bra     inplop
  3119.  
  3120.         getchr:                             ;get 1 character from keyboard
  3121.                move.l  #1,d3                ;1 character
  3122.                move.l  conhandle,d1
  3123.                lea     inbuff,a1            ;buffer-address
  3124.                move.l  a1,d2
  3125.                move.l  dosbase,a6
  3126.                jsr     read(a6)
  3127.                clr.l   d0
  3128.                move.b  inbuff,d0
  3129.                rts
  3130.  
  3131.  
  3132.         mytext:     dc.b 'Directory of Diskette: DFO:',10,13,10,13,0,0
  3133.         dosname:    dc.b 'dos.library',0,0
  3134.         presskey:   dc.b 'Press thr Return key!!',0
  3135.                align.w
  3136.         dosbase:    dc.l 0
  3137.         consolname: dc.b 'CON:0/100/640/100/** Directory-Test **',0
  3138.         name:       dc.b 'DFO:',0
  3139.                align.w
  3140.         locksav:    dc.l 0
  3141.         fileinfo:   ds.l 20
  3142.         conhandle:  dc.l 0
  3143.         inbuff:     DS.B 8
  3144.         inline:     DS.B 180
  3145.         chbuff      DS.B 82
  3146.  
  3147.                end
  3148.  
  3149.         The FileInfoBlock contains the following entries:
  3150.  
  3151.         Offset   Name             Meaning
  3152.         ----------------------------------------------------------------
  3153.           0      DiskKey.L        Disk Number
  3154.           4      DieEntryType.L   Entry Type (+=Directory,-=File)
  3155.           8      FileName         108 bytes with the filename
  3156.          116     Protection.L     File Protected?
  3157.          120     EntryType.L      Entry type
  3158.          124     Size.L           Length of file in bytes
  3159.          128     NumBlocks.L      Number of blocks
  3160.          132     Days.L           Creation day
  3161.          136     Minute.L         Creation time
  3162.          140     Tick.L           Creation time
  3163.          144     Comment          116 bytes with comments
  3164.  
  3165.         If you want to have the program output the file length as well,you
  3166.         can read the length with "move.l fileinfo+124,d0"and then use a
  3167.         conversion routine to produce a decimal number.You can output this
  3168.         result with the name.
  3169.  
  3170.       6.5.7.Direct Access To Disk.
  3171.       ----------------------------                                        
  3172.         There isn't a simple function in the library for accessing single 
  3173.         disk sectors.Here,you must work with a device just like you did
  3174.         with speech output.This time you'll be working with the trackdisk.
  3175.         device.
  3176.         You want to work with this device to directly program the disk
  3177.         drives.Once you've built up the necessary program machinery,you
  3178.         can experiment with various commands for disk access.Remember that
  3179.         an error can cause the disk to be modified and thus unusable.Make
  3180.         sure you're using a non-essential disk.Don't use one which
  3181.         contains your only copy of something.                             
  3182.         The initialization here is similar to that for speech output.Here
  3183.         is the initialization routine for your program:
  3184.  
  3185.         ;** Direct disk access via trackdisk.device ** (6.5.7)
  3186.  
  3187.         openlib    =-408
  3188.         closelib   =-414
  3189.         execbase   = 4
  3190.         open       =-30
  3191.         close      =-36
  3192.         opendevice =-444
  3193.         closedev   =-450
  3194.         sendIo     =-462
  3195.         read       =-30-12
  3196.         write      =-30-18
  3197.         waitforch  =-30-174
  3198.         mode_old   = 1005
  3199.  
  3200.         run:                             
  3201.                bsr     init                 ;initialization                     
  3202.                bra     test                 ;system-test
  3203.  
  3204.         init:                               ;initialize and open system
  3205.                move.l  execbase,a6          ;pointer to exec.library
  3206.                lea     dosname,a1
  3207.                moveq   #0,d0
  3208.                jsr     openlib(a6)          ;open dos.library
  3209.                move.l  d0,dosbase
  3210.                beq     error
  3211.                lea     diskio,a1            ;pointer to disk I/O area
  3212.                move.l  #diskrep,14(a1)      ;pointer to port
  3213.                clr.l   d0                   ;drive 0 (built in)
  3214.                clr.l   d1                   ;no flags
  3215.                lea     trddevice,a0         ;pointer to device name
  3216.                jsr     opendevice(a6)       ;open trackdisk.device
  3217.                tst.l   d0                   ;error?
  3218.                bne     error                ;yes!
  3219.                move.l  #consolname(pc),d1   ;console definition
  3220.                move.l  #mode_old,d2         ;old mode
  3221.                move.l  dosbase,a6           ;dos base address
  3222.                jsr     open(a6)             ;open window
  3223.                tst.l   d0                   ;error?
  3224.                beq     error                ;yes!
  3225.                move.l  d0,conhandle         ;else save handle
  3226.                rts                          ;done
  3227.  
  3228.         test:                               ;place for test routine
  3229.  
  3230.  
  3231.         And now for the functions that take care of the various messages
  3232.         at the end of the program.
  3233.  
  3234.  
  3235.         error:
  3236.                move.l  #-1,d7               ;flag for error (for SEKA)
  3237.  
  3238.         qu:
  3239.                move.l  execbase,a6          ;exec base address
  3240.                lea     diskio,a1            ;pointer to disk I/O
  3241.                move.l  32(a1),d7            ;IO_ACTUAL in D7 (for testing)
  3242.                move    #9,28(a1)            ;command motor on/off
  3243.                move.l  #0,36(a1)            ;0=off,1=on,so turn motor
  3244.                jsr     sendio(a6)           ;off
  3245.                move.l  conhandle,d1         ;close window
  3246.                move.l  dosbase,a6
  3247.                jsr     close(a6)
  3248.                move.l  dosbase,d1           ;close dos.lib
  3249.                move.l  execbase,a6
  3250.                jsr     closelib(a6)
  3251.                lea     diskio,a1
  3252.                jsr     closedev(a6)         ;close trackdisk.device
  3253.                rts
  3254.  
  3255.  
  3256.         Lets not forget the routine that waits for the user to press
  3257.         <Return>,so that you can watch the effects of the test function in
  3258.         peace:
  3259.  
  3260.         getchr:                             ;get a character from keyboard
  3261.                move.l  #1,d3                ;1 character
  3262.                move.l  conhandle,d1         ;window handle
  3263.                move.l  #inbuff,d2           ;buffer address
  3264.                move.l  dosbase,a6           ;dos base address
  3265.                jsr     read(a6)             ;read character
  3266.                rts                          ;thats it
  3267.  
  3268.  
  3269.         The last thing you need is the section of code that declares the
  3270.         text and data fields that your program needs:                     
  3271.                                                                           
  3272.         dosname:       dc.b  'dos.library',0
  3273.                align
  3274.         consolname:    dc.b  'RAW:0/100/640/50/** Wait window',0
  3275.                align
  3276.         trddevice:     dc.b  'trackdisk.device',0
  3277.                align
  3278.         dosbase:       dc.l 0               ;dos base address
  3279.         conhandle:     dc.l 0               ;window handle
  3280.         inbuff:        blk.b 80,0           ;keyboard buffer
  3281.         diskio:        blk.l 20,0           ;I/O structure
  3282.         diskrep:       blk.l 8,0            ;I/O port
  3283.         diskbuff:      blk.b 512*2,0        ;place for 2 sectors
  3284.  
  3285.         There,now you've done with the set up work.Lets look at how you
  3286.         can give commands to the disk drives.The first and easiest command
  3287.         is the one for turning the drive motor on and off.You've already
  3288.         seen this command in the program.This is command number nine.This
  3289.         number goes in the command word of the I/O structure (bytes 28 and
  3290.         29 of the structure).
  3291.         You need to pass a parameter that lets the computor know whether
  3292.         to turn the motor off or on.This information goes in the I/O long
  3293.         word that starts at byte 36:its zero for off,and one for on.
  3294.         You already chose the motor that should be turned on or off when
  3295.         you opened the device.You put the number of the chosen disk drive
  3296.         in D0-in your case you put a zero there because you are using the
  3297.         DFO:disk drive.
  3298.         Heres an overview of the commands you can use to access
  3299.         information on the disk:
  3300.  
  3301.         No    Name          Function
  3302.         -----------------------------------------------------------------
  3303.         2     READ          Read one or more sectors
  3304.         3     WRITE         Write sectors
  3305.         4     UPDATE        Update the track buffer
  3306.         5     CLEAR         Erase track buffer
  3307.         9     MOTOR         Turn motor on/off
  3308.         10    SEEK          Search for a track
  3309.         11    FORMAT        Format tracks
  3310.         12    REMOVE        Initialize routine that is called when you
  3311.                             remove the disk
  3312.         13    CHANGENUM     Find out number of disk changes
  3313.         14    CHANGESTATE   Test if disk is in drive
  3314.         15    PROTSTATUS    Test if disk is write protected
  3315.  
  3316.         You've already learned about command number nine.Lets look at the
  3317.         three commands you can use to make tests.These are the last three
  3318.         commands.They put a return value in the long word that begins in
  3319.         the 32nd byte in the I/O structure.This value was written in D7 in
  3320.         the program above for testing purposes.You can read its contents  
  3321.         directly if you ran the program with AssemPro.
  3322.         Here is a simple routine that you can use to run one of these
  3323.         commands with:
  3324.  
  3325.         test:                               ; (6.5.7B)
  3326.                lea     diskio,a1            ;pointer to I/O structure
  3327.                move    #13,28(a1)           ;pass command (for example 13)
  3328.                move.l  execbase,a6          ;execbase address in A6
  3329.                jsr     sendio(a6)           ;call function
  3330.  
  3331.         If CHANGENUM (command 13) is executed,in D7 you'll get the number
  3332.         of times a disk was taken out and put in the drive.If you call the
  3333.         program,you'll get a value back.If you take the disk out and put
  3334.         it back in,the number is two higher the next time you call the
  3335.         program.
  3336.         The CHANGESTATE command (command 14) tells whether a disk is in
  3337.         the drive or not.If one is,a zero comes back.Otherwise,a $FF is
  3338.         returned.
  3339.         You get the same values back from the PROTSTATUS function (command
  3340.         15).Here a zero means that the disk isn't write protected,while
  3341.         $FF means that it is.
  3342.         Now lets look at the READ and WRITE functions.These operations
  3343.         need a few more parameters than the status functions.You need to
  3344.         pass the following parameters: 
  3345.  
  3346.         The address of the I/O buffer in the data pointer,the number of
  3347.         bytes to be transfered in I/O length,and the data address on the
  3348.         disk in I/O offset. 
  3349.  
  3350.         The number of data bytes must be a multiple of 512,since every
  3351.         sector is 512 bytes,and only whole sectors can be read.
  3352.  
  3353.         The data address is the number of the first byte in the sector.If 
  3354.         you want to use the first sector,the offset is zero.For the second
  3355.         sector,its 512,etc...The formula is:
  3356.  
  3357.             offset = (sector_number -1) *512
  3358.  
  3359.         Here is a routine that loads the first two sectors of the disk
  3360.         into the buffer:
  3361.  
  3362.         test:  (6.5.7C)
  3363.                lea     diskio,a1           
  3364.                move    #2,28(a1)           ;command:READ
  3365.                move.l  #diskbuff,40(a1)    ;buffer
  3366.                move.l  #2*512,36(a1)       ;length:2 sectors
  3367.                move.l  #0*512,44(a1)       ;offset:0 sectors
  3368.                move.l  execbase,a6         ;exec base address
  3369.                jsr     sendio(a6)          ;start function
  3370.  
  3371.         Start the program from the debugger and then look at the buffers  
  3372.         contents after the program ends.You can find out the format of the
  3373.         disk here.If you want to read a sector thats being used,change the
  3374.         0 in the offset definition to 700 and start again.Its highly
  3375.         probable that theres some data there.
  3376.         To modify and write back the data that you've read from the disk, 
  3377.         you need command number three,the WRITE command.The parameters are
  3378.         the same.
  3379.         If you've executed the WRITE commandyou're probably wondering why
  3380.         the disk light did'nt go on.Thats because the Amiga writes a track
  3381.         that as been read into a buffer on its own.It WRITE's data there
  3382.         as well.It won't write the data to disk until another track is
  3383.         accessed.
  3384.         You can have the data updated directly as well using command four,
  3385.         the UPDATE command.
  3386.         Command 11,the FORMAT command,is also quite interesting.This
  3387.         command needs a data field that is 11*512=5632 bytes long-the
  3388.         length of a track.The offset must be a multiple of this number so 
  3389.         that you start at the beginning of a track.
  3390.         The length must be a multiple of 5632 as a result.If several
  3391.         tracks are formatted,each track is filled with the same data.
  3392.         You can use this function to easy write a disk copy program.You
  3393.         READ the source disk and then FORMAT the corresponding track on
  3394.         the destination disk.Thats how the DiskCopy program works-it
  3395.         reformats the destination disk.
  3396.         Command ten,the SEEK command,just needs the offset.It moves the
  3397.         Read/Write head of the drive to the position specified without
  3398.         making a disk access or testing if its at the right position.
  3399.         Command 12,the REMOVE command,is used to install an interrupt
  3400.         routine that is called when the disk is removed from the disk
  3401.         drive.The address of the interrupt structure is passed in the data
  3402.         pointer of the I/O structure.If theres a zero here,the interrupt  
  3403.         routine is turned off.
  3404.  
  3405.         Heres a complete example program in AssemPro format:
  3406.  
  3407.         ;***** Track disk-Basic function  10/86 S.D. *****
  3408.  
  3409.                ILABEL ASSEMPRO:includes/Amiga.l   :AssemPro only
  3410.  
  3411.         openlib      =-30-378
  3412.         closelib     =-414
  3413.         ;execbase    = 4                    ;defined in INIT_AMIGA
  3414.  
  3415.         * calls to amiga dos:
  3416.  
  3417.         open         =-30
  3418.         close        =-30-6
  3419.         opendevice   =-444
  3420.         closedev     =-450
  3421.         sendIo       =-462
  3422.         read         =-30-12
  3423.         write        =-30-18
  3424.         waitforch    =-30-174
  3425.         mode_old     = 1005
  3426.  
  3427.                INIT_AMIGA                   ;AssemPro only
  3428.  
  3429.         run:
  3430.                bsr     init                 ;initialization
  3431.                bra     test                 ;system test
  3432.  
  3433.         init:                               ;system initialization and
  3434.                                             ;open 
  3435.                move.l  execbase,a6          ;pointer to exec-library
  3436.                lea     dosname,a1
  3437.                moveq   #0,d0
  3438.                jsr     openlib(a6)          ;open dos-library
  3439.                move.l  d0,dosbase
  3440.                beq     error
  3441.  
  3442.                lea     diskio,a1
  3443.                move.l  #diskrep,14(a1)
  3444.                clr.l   d0
  3445.                clr.l   d1
  3446.                lea     trddevice,a0
  3447.                jsr     opendevice(a6)       ;open trackdisk.device
  3448.                tst.l   d0
  3449.                bne     error
  3450.  
  3451.         bp:
  3452.                lea     consolname(pc),a1    ;console-definition
  3453.                move.l  #mode_old,d0
  3454.                bsr     openfile             ;console open
  3455.                beq     error
  3456.                move.l  d0,conhandle
  3457.  
  3458.                rts
  3459.  
  3460.         test:
  3461.                bsr     accdisk
  3462.  
  3463.                bsr     getchr               ;wait for character
  3464.                bra     qu
  3465.  
  3466.         error:
  3467.                move.l  #-1,d7               ;flag
  3468.  
  3469.         qu:
  3470.                move.l  execbase,a6
  3471.                lea     diskio,a1
  3472.                move    #9,28(a1)
  3473.                move.l  #0,36(a1)
  3474.                jsr     sendio(a6)
  3475.  
  3476.                move.l  conhandle,d1         ;window close
  3477.                move.l  dosbase,a6
  3478.                jsr     close(a6)
  3479.  
  3480.                move.l  dosbase,a1           ;dos.lib close
  3481.                move.l  execbase,a6
  3482.                jsr     closelib(a6)
  3483.  
  3484.                lea     diskio,a1
  3485.                move.l  32(a1),d7
  3486.                jsr     closedev(a6)
  3487.  
  3488.                EXIT_AMIGA                   ;AssemPro only
  3489.  
  3490.         openfile:                           ;open file
  3491.                move.l  a1,d1                ;pointer to the I/O-definition
  3492.                                             ;text
  3493.                move.l  d0,d2
  3494.                move.l  dosbase,a6
  3495.                jsr     open(a6)
  3496.                tst.l   d0
  3497.                rts
  3498.  
  3499.         scankey:                            ;test for key
  3500.                move.l  conhandle,d1                      
  3501.                move.l  #500,d2              ;wait value
  3502.                move.l  dosbase,a6
  3503.                jsr     waitforch(a6)
  3504.                tst.l   d0
  3505.                rts
  3506.  
  3507.         getchr:                             ;get one character from
  3508.                                             ;keyboard
  3509.                move.l  #1,d3                ;1 character
  3510.                move.l  conhandle,d1
  3511.                lea     inbuff,a1            ;buffer-address
  3512.                move.l  a1,d2
  3513.                move.l  dosbase,a6
  3514.                jsr     read(a6)
  3515.                clr.l   d0
  3516.                move.b  inbuff,d0
  3517.                rts
  3518.  
  3519.         accdisk:
  3520.                lea     diskio,a1
  3521.                move    #2,28(a1)            ;command:READ                 
  3522.                move.l  #diskbuff,40(a1)     ;buffer
  3523.                move.l  #2*512,36(a1)        ;length:2 sectors
  3524.                move.l  #20*512,44(a1)       ;offset: n sectors
  3525.                move.l  execbase,a6
  3526.                jsr     sendio(a6)
  3527.                rts
  3528.  
  3529.         dosname:       dc.b 'dos.library',0,0
  3530.                align.w
  3531.         dosbase:       dc.l 0
  3532.         consolname:    dc.b 'RAW:0/100/640/100/** Test-Window S.D.V0.1',0
  3533.         trddevice:     dc.b 'trackdisk.device',0
  3534.                align.w
  3535.         conhandle      dc.l 0
  3536.         inbuff:        ds.b 8                                             
  3537.         diskio:        ds.l 20,0                                          
  3538.         diskrep:       ds.l 8,0                                           
  3539.         diskbuff:      ds.b 512*2,0                                       
  3540.                                                                           
  3541.                end
  3542.            
  3543.                             NOW LOAD PART THREE
  3544.                             
  3545. end.
  3546.